﻿/******************************************************************************\
    Html.cpp contains functions generating html pages.
    It's used with acm server. See main.cpp for details.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#include ".\Html.h"
#include ".\Common.h"
#include <Common\String.h>
#include <Common\Time.h>
#include <Common\Memory.hpp>
#include ".\Action.h"
#include ".\ConfigFile.h"
#include ".\Error.h"
using namespace std;
using namespace nsContestantDataBase;
using namespace nsClientDataBase;
using namespace nsPluginDataBase;
using namespace nsContestDataBase;
using namespace nsContestContestantDataBase;
using namespace nsContestProblemDataBase;
using namespace nsProblemDataBase;
using namespace nsLanguageDataBase;
using namespace nsContestContestantProblemDataBase;

	// Получение информации о клиенте
	// Проверка прав доступа к странице
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы

int WideEscape( const wchar_t *source, int source_length, wchar_t *destination )
{
	int destination_length = 0;
	for( int i = 0; i < source_length; ++i )
	{
		wchar_t *str;
		switch( source[ i ] )
		{
		case L'<': 
			str = L"&lt;";
			break;
		case L'>': 
			str = L"&gt;";
			break;
		case L'\'': 
			str = L"&#39;";
			break;
		case L'"': 
			str = L"&quot;";
			break;
		case L'&': 
			str = L"&amp;";
			break;
		default:
			if( destination != NULL )
				destination[ destination_length ] = source[ i ];
			++destination_length;
			continue;
		}
		for( int j = 0; str[ j ] != L'\0'; ++j )
		{
			if( destination != NULL )
				destination[ destination_length ] = str[ j ];
			++destination_length;
		}
	}
	return destination_length;
}

static string Escape( const string &str )
{
	int WideCharLength = MultiByteToWideChar( CP_UTF8, 0, str.c_str(), str.length(), NULL, 0 );
	if( WideCharLength == 0 )
		return "";
	cMemory< wchar_t > WideChar( WideCharLength );
	MultiByteToWideChar( CP_UTF8, MB_ERR_INVALID_CHARS, str.c_str(), str.length(), WideChar, WideCharLength );

	int NewWideCharLength = WideEscape( WideChar, WideCharLength, NULL );
	cMemory< wchar_t > NewWideChar( NewWideCharLength );
	WideEscape( WideChar, WideCharLength, NewWideChar );

	int MultiByteLength = WideCharToMultiByte( CP_UTF8, 0, NewWideChar, NewWideCharLength, NULL, 0, NULL, NULL );
	if( MultiByteLength == 0 )
		return "";
	cMemory< char > MultiByte( MultiByteLength );
	WideCharToMultiByte( CP_UTF8, 0, NewWideChar, NewWideCharLength, MultiByte, MultiByteLength, NULL, NULL );

	return string( MultiByte, MultiByteLength );
}

static string GetPluginTitle( const sPluginData &plugin_data )
{
	string title;
	if( ( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) )
	{
		if( plugin_data.Handle != NULL )
		{	
			unsigned long title_length;
			if( plugin_data.MainProc( GET_TITLE_LENGTH, 0, &title_length ) )
			{
				cMemory< char > _title( title_length + 1 );
				if( plugin_data.MainProc( GET_TITLE, 0, _title ) )
					title = _title;
				else
					title = Escape( plugin_data.Name ) + " (unable to get title)";
			}
			else
				title = Escape( plugin_data.Name ) + " (unable to get title length)";
		}
		else
			title = Escape( plugin_data.Name ) + " (unable to load plugin)";
	}
	else
		title = Escape( plugin_data.Name ) + " (disabled)";
	return title;
}

static string GetResult( const sContestContestantProblemData &contest_contestant_problem_data )
{
	string result;
	switch( contest_contestant_problem_data.Result )
	{
	case RESULT_TESTING_INTERRUPTED:
		result += "<font class='TI'>Testing Interrupted";
		break;
	case RESULT_SUBMISSION_ERROR:
		result += "<font class='SE'>Submission Error";
		break;
	case RESULT_WAITING:
		result += "<font class='WT'>Waiting...";
		break;
	case RESULT_RUNNING:
		result += "<font class='RN'>Running...";
		break;
	case RESULT_ACCEPTED:
		result += "<font class='AC'>Accepted";
		break;
	case RESULT_WRONG_ANSWER:
		result += "<font class='WA'>Wrong Answer";
		break;
	case RESULT_TIME_LIMIT_EXCEEDED:
		result += "<font class='TL'>Time Limit Exceeded";
		break;
	case RESULT_RUN_TIME_ERROR:
		result += "<font class='RE'>Runtime Error";
		break;
	case RESULT_MEMORY_LIMIT_EXCEEDED:
		result += "<font class='ML'>Memory Limit Exceeded";
		break;
	case RESULT_OUTPUT_LIMIT_EXCEEDED:
		result += "<font class='OL'>Output Limit Exceeded";
		break;
	case RESULT_COMPILATION_ERROR:
		result += "<font class='CE'>Compilation Error";
		break;
	case RESULT_PRESENTATION_ERROR:
		result += "<font class='PE'>Presentation Error";
		break;
	case RESULT_SECURITY_VIOLATION:
		result += "<font class='SV'>Security Violation";
		break;
	case RESULT_SOURCE_LIMIT_EXCEEDED:
		result += "<font class='SL'>Source Limit Exceeded";
		break;
	default:
		result += StringPrintf( "<font class='UE'>Unknown Error (%ld)", contest_contestant_problem_data.Result );
		break;
	}
	if( contest_contestant_problem_data.TestNumber != 0 )
		result += StringPrintf( " #%hu", contest_contestant_problem_data.TestNumber );
	result += "</font>";
	return result;
}

static string Menu( const sContestantData &client_contestant_data )
{
	string result;
//	result += "<a class='menu' href='/home.html'>Home</a>";
	if( client_contestant_data.Status & STATUS_CONTESTS_BROWSING )
		result += "<br><a class='menu' href='/contests.html'>Contests</a>";
	if( client_contestant_data.Status & STATUS_CONTESTANTS_BROWSING )
		result += "<br><a class='menu' href='/contestants.html'>Contestants</a>";
	if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
		result += "<br><a class='menu' href='/contestant_contest_problems.html'>Status</a>";
	if( client_contestant_data.Status & STATUS_CLIENTS_BROWSING )
		result += "<br><a class='menu' href='/clients.html'>Clients</a>";
	if( client_contestant_data.Status & STATUS_PLUGINS_BROWSING )
		result += "<br><a class='menu' href='/plugins.html'>Plugins</a>";
	if( client_contestant_data.Status & STATUS_PROXY_EDITING )
		result += "<br><a class='menu' href='/proxy.html'>Proxy</a>";
	result += "<br><a class='menu' href='/about.html'>About</a>";
	if( client_contestant_data.Key == BAD_KEY )
		result += "<br><a class='menu' href='/login.html'>Login</a>";
	else
		result += "<br><a class='menu' href='/logout.action'>Logout</a>";
	if( client_contestant_data.Status & STATUS_MANAGE )
		result += "<br><a class='menu' href='/shutdown.action'>Shutdown</a>";
	return result;
}

static bool GetContestantDataById( unsigned long contestant_id, sContestantData &contestant_data )
{
	if( ContestantDataBase->GetByKey( contestant_id, contestant_data ) )
		return true;
	contestant_data.Key = BAD_KEY;
	contestant_data.Status = STATUS_GUEST;
	return false;
}

static string MainHtml( const sContestantData &client_contestant_data, const cFormat parameter, const string &main_frame )
{
	string result = "<html>";
	result += "<head>";
	result += "<title>ACM Server</title>";
	result += "<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>";
	result += "<link rel='stylesheet' type='text/css' href='/style.css'>";
	result += "<link rel='shortcut icon' href='/favicon.ico'>";
	long refresh;
	if( GetVariable( parameter, "refresh", refresh ) && refresh != 0 )
	{
		result += StringPrintf( "<meta http-equiv='refresh' content='%ld'>", refresh );
	}
	result += "</head>";
	result += "<body>";
	result += "<table class='main' cellspacing='0'>";
	result += "<tr>";
	result += "<td class='profile_box'>";
	if( client_contestant_data.Key == BAD_KEY )
	{
		result += "<form action='/login.action' method='post' enctype='application/x-www-form-urlencoded'>";
		result += "<div class='profile_box'>";
		result += "Login:&nbsp;<input class='profile_box' type='text' name='login' value='' maxlength='64' size='12'>&nbsp;";
		result += "Password:&nbsp;<input class='profile_box' type='password' name='password' value='' maxlength='64' size='12'>&nbsp;";
		result += "<input class='profile_box' type='submit' value='Login'>";
		result += "</div>";
		result += "</form>";
	}
	else
	{
		result += "<form action='/logout.action' method='get' enctype='application/x-www-form-urlencoded'>";
		result += "<div class='profile_box'>";
		result += StringPrintf( "You are logged in as <a class='profile_box' href='/contestant.html?contestant_id=%d'>%s</a>&nbsp;&nbsp;&nbsp;", client_contestant_data.Key, Escape( client_contestant_data.Name ).c_str() );
		result += "<input class='profile_box' type='submit' value='Logout'>";
		result += "</div>";
		result += "</form>";
	}
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='caption'>";
	result += "<font class='caption'>ACM Server</font>";
	result += "</td>";
	result += "</tr>";
	result += "<tr height='100%'>";
	result += "<td class='main'>";
	result += "<table class='main' cellspacing='0'>";
	result += "<tr height='100%'>";
	result += "<td class='menu'>";
	result += Menu( client_contestant_data );
	result += "</td>";
	result += "<td class='main'>";
	long error;
	if( GetVariable( parameter, "error", error ) )
	{
		result += "<center>";
		result += StringPrintf( "<p class='error'>%s</p>", GetError( error ).c_str() );
		result += "</center>";
	}
	result += main_frame;
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='subscription'>";
	result += "<hr class='subscription'>";
	result += StringPrintf( "<font class='subscription_title'><a href='http://acm-server.ru/' style='text-decoration: none;'><font class='subscription_title'>ACM Server</font></a> (%s)</font>", Version );
	result += "<br>";
	result += "<font class='subscription_info'>&copy; Victor Vinogradov (fly3333@gmail.com)</font>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "</body>";
	result += "</html>";
	return result;
}

static void InitializeControlVariables( int &start, int &finish, int &count, const cFormat parameter )
{
	long a;
	if( !GetVariable( parameter, "start", a ) )
		a = 0;
	start = a;
	if( !GetVariable( parameter, "finish", a ) )
		a = start + 16;
	finish = a;
	count = 0;
}

static string TableControlBar( int start, int finish, int count, const cFormat parameter )
{
	string param_str;
	for( cFormat::const_iterator parameter_iterator = parameter.Begin(); parameter_iterator != parameter.End(); ++parameter_iterator )
	{
		if( parameter_iterator->first == "start" ||
			 parameter_iterator->first == "finish" )
			continue;
		param_str += parameter_iterator->first + "=" + parameter_iterator->second.AsString() + "&";
	}
	string result;
	result += "<div class='table_control'>";
	if( finish - start >= 8 )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='table_control' href='?%sstart=%d&finish=%d'>Half</a>", param_str.c_str(), start, ( finish + start ) / 2 );
	else
		result += "&nbsp;&nbsp;&nbsp;<font class='table_control'>Half</font>";
	if( start != 0 )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='table_control' href='?%sstart=%d&finish=%d'>First %d</a>", param_str.c_str(), 0, finish - start, finish - start );
	else
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<font class='table_control'>First %d</font>", finish - start );
	if( 2 * start - finish > 0 )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='table_control' href='?%sstart=%d&finish=%d'>Prev %d</a>", param_str.c_str(), 2 * start - finish, start, finish - start );
	else
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<font class='table_control'>Prev %d</font>", finish - start );
	if( 2 * finish - start < count )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='table_control' href='?%sstart=%d&finish=%d'>Next %d</a>", param_str.c_str(), finish, 2 * finish - start, finish - start );
	else
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<font class='table_control'>Next %d</font>", finish - start );
	if( finish != count && finish - start < count )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='table_control' href='?%sstart=%d&finish=%d'>Last %d</a>", param_str.c_str(), count - finish + start, count, finish - start );
	else
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<font class='table_control'>Last %d</font>", finish - start );
	if( finish - start <= 1024 )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='table_control' href='?%sstart=%d&finish=%d'>Double</a>", param_str.c_str(), start, finish * 2 - start );
	else
		result += "&nbsp;&nbsp;&nbsp;<font class='table_control'>Double</font>";
	result += "</div>";
	return result;
}

static string RefreshBar( cFormat parameter )
{
	string result;
	long refresh;
	if( !GetVariable( parameter, "refresh", refresh ) )
		refresh = 0;
	result += "<div class='refresh_control'><font class='refresh_control'>Refresh every:";
	for( int i = 15; i <= 240; i *= 2 )
	{
		parameter[ "refresh" ] = StringPrintf( "%d", i );
		if( i == refresh )
			result += StringPrintf( "&nbsp;&nbsp;&nbsp;<font style='font-weight: bold;'>%d</font>", i );
		else
			result += StringPrintf( "&nbsp;&nbsp;&nbsp;<a class='refresh_control' href='?%s'>%d</a>", MakeParameters( parameter ).c_str(), i );
	}
	parameter.Delete( "refresh" );
	if( refresh == 0 )
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;seconds&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<font style='font-weight: bold;'>no refresh</font>" );
	else
		result += StringPrintf( "&nbsp;&nbsp;&nbsp;seconds&nbsp;&nbsp;&nbsp;|&nbsp;&nbsp;&nbsp;<a class='refresh_control' href='?%s'>no refresh</a>", MakeParameters( parameter ).c_str() );
	result += "</font></div>";
	if( refresh != 0 )
		parameter[ "refresh" ] = StringPrintf( "%ld", refresh );
	return result;
}

// Основные страницы

//string HomeHtml( const sClientData &client_data, const cFormat parameter )
//{
//	// Получение информации о клиенте
//	sContestantData client_contestant_data;
//	GetContestantDataById( client_data.ContestantId, client_contestant_data );
//	// Проверка прав доступа к странице
//	// Извлечение параметров
//	// Чтение из базы
//	// Генерация страницы
//	string result;
//	result += "<div class='home'>";
//	result += "<p class='news'>";
////	result += "<font class='news_date'>31.01.2008</font>&nbsp;&nbsp;&nbsp;<font class='news_text'>Server was created.</font>";
//	result += "<center><h1>Welcome to the ACM Server!</h1></center><br>";
//	result += "It is a server for holding virtual contests by the ACM rules. The contest may base on problems of the most popular problem achives with online judge system such as Timus Online Judge, UVa Online Judge or Peking University Online Judge System. Visit acm-server.ru for downloads and updates.<br>";
//	result += "</p>";
//	result += "</div>";
//	return MainHtml( client_contestant_data, parameter, result );
//}

std::string StyleCss()
{
	string result;
	/* Common */
	result += "body { background-color: ghostwhite; padding: 0px; margin: 0px; }\r\n";
	result += "table { border-style: dashed; border-width: 0px; border-color: black; }\r\n";
	result += "table.main { margin: 0px; width: 100%; height: 100%; }\r\n";
	result += "td { padding: 0px; margin: 0px; border-style: dashed; border-color: black; border-width: 0px; }\r\n";
	result += "td.main { text-align: left; vertical-align: top; padding: 5px; }\r\n";
	result += "hr { border-color: #e8e8f8; border-style: solid; border-width: 1px; }\r\n";

	result += "a { font-family: times new roman; font-size: 16px; }\r\n";
	result += "a:link    { text-decoration: underline; color: royalblue; }\r\n";
	result += "a:visited { text-decoration: underline; color: royalblue; }\r\n";
	result += "a:hover   { text-decoration: none; color: crimson; }\r\n";
	result += "a:active  { text-decoration: none; color: crimson; }\r\n";

	result += "a.command { font-family: times new roman; font-size: 16px; }\r\n";
	result += "img.command { border-style: solid; border-width: 0px; border-color: black; margin: 1px; }\r\n";
//	result += "a.title { font-family: garamond, times new roman; font-size: 24px; font-weight: bold; margin-top: 20px; text-align: center; }\r\n";

	result += "p.error { font-family: garamond, arial; font-size: 20px; font-weight: bold; color: red; }\r\n";
	result += "font.error { font-family: comic sans ms, trebuchet ms, arial; font-size: 16px; color: red; }\r\n";

	result += "h1.title { font-family: garamond, times new roman; font-size: 24px; color: indigo; font-weight: bold; margin-top: 20px; }\r\n";
	result += "h2.comment { font-family: times new roman; font-size: 15px; color: indigo; font-style: italic; }	\r\n";
	result += "input.text { font-family: trebuchet ms, tahoma, arial; font-size: 13px; }\r\n";
	result += "font.form { font-family: tahoma, arial; font-size: 16px; }\r\n";
	result += "input.submit { font-family: trebuchet ms, tahoma, arial; font-size: 13px; margin: 10px; width: 75px; font-weight: bold; }\r\n";

	result += "th.list { padding: 5px; font-family: trebuchet ms, arial; font-size: 16px; font-weight: bold; text-align: center; }\r\n";
	result += "tr.record:hover { background-color: #f0f0ff; }\r\n";
	result += "td.record { padding: 5px; font-family: trebuchet ms, arial; font-size: 16px; }\r\n";
	result += "a.record { font-family: comic sans ms, trebuchet ms, arial; font-size: 16px; }\r\n";

	result += "td.variable_name { padding: 5px; padding-right: 15px; text-align: left; font-family: bookman old style, times new roman; font-size: 16px; }\r\n";
	result += "td.variable_value { padding: 5px; padding-left: 15px; text-align: right; font-family: bookman old style, times new roman; font-size: 16px; }\r\n";

	result += "table.edit { width: 100%; border-style: dashed; border-color: red; border-width: 0px; }\r\n";
	result += "td.edit_field_name { width: 100px; text-align: right; vertical-align: center; font-family: tahoma, arial; font-size: 16px; padding: 5px; }\r\n";
	result += "td.edit_field_value { text-align: left; vertical-align: center; font-family: tahoma, arial; font-size: 16px;  padding: 5px; }\r\n";

	result += "div.delete { text-align: center; width: 200px; padding: 5px; border-color: red; border-style: dotted; border-width: 3px; background-color: aliceblue; }\r\n";
	result += "p.delete { font-family: arial; font-size: 16px; }\r\n";
	result += "a.delete { font-family: trebuchet ms, arial; font-size: 16px; }\r\n";

	result += "pre.code { font-family: courier; font-size: 11px; padding: 5px; border-style: dashed; border-color: blue; border-width: 3px; background-color: aliceblue; text-align: left; }\r\n";
	result += "pre.compilation_error { font-family: courier; font-size: 11px; padding: 5px; border-style: dashed; border-color: red; border-width: 3px; background-color: lavenderblush; text-align: left; }\r\n";

	result += "div.table_control       { text-align: right; padding: 10px; }\r\n";
	result += "a.table_control         { font-family: arial; font-size: 12px; font-weight: normal; }\r\n";
	result += "a.table_control:link    { text-decoration: none; color: mediumblue; }\r\n";
	result += "a.table_control:visited { text-decoration: none; color: mediumblue; }\r\n";
	result += "a.table_control:hover   { text-decoration: underline; color: crimson; }\r\n";
	result += "a.table_control:active  { text-decoration: underline; color: crimson; }\r\n";
	result += "font.table_control      { font-family: arial; font-size: 12px; font-weight: normal; color: black; }\r\n";

	result += "div.refresh_control       { text-align: right; padding: 10px; }\r\n";
	result += "a.refresh_control         { font-family: arial; font-size: 12px; font-weight: normal; }\r\n";
	result += "a.refresh_control:link    { text-decoration: none; color: mediumblue; }\r\n";
	result += "a.refresh_control:visited { text-decoration: none; color: mediumblue; }\r\n";
	result += "a.refresh_control:hover   { text-decoration: underline; color: crimson; }\r\n";
	result += "a.refresh_control:active  { text-decoration: underline; color: crimson; }\r\n";
	result += "font.refresh_control      { font-family: arial; font-size: 12px; font-weight: normal; color: black; }\r\n";

	/* Profile box */
	result += "td.profile_box { text-align: right; }\r\n";
	result += "div.profile_box { float: right; border-width: 1px; border-color: red; border-style: dashed; background-color: aliceblue; font-family: arial narrow; font-size: 13px; padding: 2px; }\r\n";
	result += "input.profile_box { font-family: arial; font-size: 11px; }\r\n";
	result += "a.profile_box { font-family: arial; font-size: 13px; }\r\n";

	/* Caption */
	result += "td.caption { text-align: center; width: 100%; }\r\n";
	result += "font.caption { color: indigo; font-family: times new roman; font-size: 32px; font-weight: bold; }\r\n";

	/* Menu */
	result += "td.menu { text-align: center; width: 150px; vertical-align: top; padding: 1px; }\r\n";
	result += "a.menu { font-family: garamond, times new roman; font-size: 19px; font-weight: bold; }\r\n";
	result += "a.menu:link    { text-decoration: underline; color: mediumblue;  }\r\n";
	result += "a.menu:visited { text-decoration: underline; color: darkslateblue; }\r\n";
	result += "a.menu:hover   { text-decoration: none; color: crimson; }\r\n";
	result += "a.menu:active  { text-decoration: none; color: crimson; }\r\n";

	/* Subscription */
	result += "td.subscription { text-align: center; width: 100%; }\r\n";
	result += "hr.subscription {}\r\n";
	result += "font.subscription_title { font-family: comic sans ms, tahoma, arial; font-size: 10px; color: lightsteelblue; }\r\n";
	result += "font.subscription_info { font-size: 10px; font-family: 'arial narrow'; color: lightsteelblue; }\r\n";

	/* Home */
	result += "div.home { padding: 5px; text-align: left; }\r\n";
	result += ".news_date { font-family: bookman old style, times new roman; font-size: 15px; font-style: italic; font-weight: bold; }\r\n";
	result += ".news_text { font-family: bookman old style, times new roman; font-size: 15px; }\r\n";
	result += "p.news { text-align: left; }\r\n";

	result += "div.login { border-style: dotted; border-width: 3px; border-color: royalblue; width: 200px; background-color: aliceblue; font-family: trebuchet ms, tahoma, arial; font-size: 18px; text-align: center; padding: 5px; font-family: times new roman; }\r\n";

	/* Submission results */
	result += "font.TI {}\r\n";
	result += "font.SE { font-weight: bold; color: red; }\r\n";
	result += "font.WT {}\r\n";
	result += "font.RN {}\r\n";
	result += "font.AC { font-weight: bold; color: green; }\r\n";
	result += "font.WA {}\r\n";
	result += "font.TL {}\r\n";
	result += "font.RE {}\r\n";
	result += "font.ML {}\r\n";
	result += "font.OL {}\r\n";
	result += "font.CE {}\r\n";
	result += "font.PE {}\r\n";
	result += "font.SV {}\r\n";
	result += "font.SL {}\r\n";
	result += "font.UE { font-weight: bold; color: red; }\r\n";
	return result;
}

string ErrorHtml( const sClientData &client_data, const string &message )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<div align='center'>";
	result += StringPrintf( "<p class='error'>%s</p>", message.c_str() );
	result += "</div>";
	return MainHtml( client_contestant_data, cFormat(), result );
}

std::string LoginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	// Извлечение параметров	
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<div style='padding: 5px'>";
	result += "<center>";
	result += "<form action='/login.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='login'>";
	result += StringPrintf( "Login:&nbsp;<input class='text' type='text' name='login' value='' maxlength='%lu' size='12'><br>", nsContestantDataBase::MAX_LOGIN_LENGTH );
	result += StringPrintf( "Password:&nbsp;<input class='text' type='password' name='password' value='' maxlength='%lu' size='12'><br>", nsContestantDataBase::MAX_PASSWORD_LENGTH );
	result += "<input class='submit' type='submit' value='Login'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";
	result += "</div>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestantsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTANTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long show_bots;
	if( !GetVariable( parameter, "show_bots", show_bots ) )
		show_bots = 0;
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<h1 class='title'>Contestants</h1>";
	result += StringPrintf( "<div width='100%' style='text-align: right;'><a href='/contestants.html?start=%d&finish=%d&show_bots=%d'>%s bots</a></div>", start, finish, show_bots ? 0 : 1, show_bots ? "hide" : "show" );
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Name</th>";
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) != STATUS_CONTESTANT_EDITING_DENIED )
	{
		result += "<th class='list' width='50px'>";
		if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_FULL )
			result += "<a class='command' href='/add_contestant.html'><img class='command' src='/plus.png' alt='add' title='Add new contestant'></a>";
		result += "</th>";
	}
	result += "</tr>";
	{
		cLocker locker( *ContestantDataBase );
		int number = 1;
		for( nsContestantDataBase::NameIterator contestant_iterator = ContestantDataBase->BeginByName(); contestant_iterator != ContestantDataBase->EndByName(); ++contestant_iterator )
		{
			if( !show_bots && contestant_iterator->Status & nsContestantDataBase::STATUS_BOT )
				continue;
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='record' href='/contestant.html?contestant_id=%lu'>%s</a>", contestant_iterator->Key, Escape( contestant_iterator->Name ).c_str() );
				result += "</td>";
				if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) != STATUS_CONTESTANT_EDITING_DENIED )
				{
					result += "<td class='record' align='center'>";
					if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) != STATUS_CONTESTANT_EDITING_HIMSELF || contestant_iterator->Key == client_data.ContestantId )
						result += StringPrintf( "<a class='command' href='/edit_contestant.html?contestant_id=%lu'><img class='command' src='/pencil.png' alt='edit' title='Edit contestant'></a>", contestant_iterator->Key );
					if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_FULL )
						result += StringPrintf( "<a class='command' href='/delete_contestant.html?contestant_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete contestant'></a>", contestant_iterator->Key );
					result += "</td>";
				}
				result += "</tr>";
			}
			++count;
			++number;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTANTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contestant_id;
	if( !GetVariable( parameter, "contestant_id", contestant_id ) )
		return ErrorHtml( client_data, "This page requires interger variable 'contestant_id'." );
	// Чтение из базы
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contestant_id, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<h1 class='title'>%s</h1>", Escape( contestant_data.Name ).c_str() );
	if( *contestant_data.Comment != '\0' )
	{
		result += "<hr>";
		result += StringPrintf( "<h2 class='comment'>%s</h2>", Escape( contestant_data.Comment ).c_str() );
	}
	//result += "<hr>";
	//result += "<table cellspacing='0' align='center'>";
	//result += "<tr>";
	//result += "<td class='variable_name'>Accepted</td>";
	//result += "<td class='variable_value'>0</td>";
	//result += "</tr>";
	//result += "</table>";
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_HIMSELF && client_data.ContestantId == contestant_id || 
		 ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_BASIC || 
		 ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_FULL )
	{
		result += "<hr>";
		result += StringPrintf( "<a class='record' href='/edit_contestant.html?contestant_id=%lu'>Edit</a>", contestant_id );
		if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_FULL )
			result += StringPrintf( "<br><a class='record' href='/delete_contestant.html?contestant_id=%lu'>Delete</a>", contestant_id );		
	}
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AddContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) != STATUS_CONTESTANT_EDITING_FULL )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/add_contestant.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Login:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='login' maxlength='%lu' value=''>", MAX_LOGIN_LENGTH );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Password:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='password' name='password' maxlength='%lu' value=''>", MAX_PASSWORD_LENGTH );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Confirmation:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='password' name='confirmation' maxlength='%lu' value=''>", MAX_PASSWORD_LENGTH );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Name:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='name' maxlength='%lu' value=''>", nsContestantDataBase::MAX_NAME_LENGTH );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Comment:</td>";
	result += "<td class='edit_field_value'>";
	result += "<textarea class='text' name='comment' rows='4'></textarea>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Status:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input type='checkbox' name='contestants_browsing' checked>Allow to browse contestants<br>";
	result += "<input type='radio' name='contestant_editing' value='0' checked>Don't allow to edit contestants<br>";
	result += "<input type='radio' name='contestant_editing' value='1'>Allow to edit himself only<br>";
	result += "<input type='radio' name='contestant_editing' value='2'>Allow to edit everyone, but don't allow to edit access rights<br>";
	result += "<input type='radio' name='contestant_editing' value='3'>Allow to edit everyone and everything<br>";
	result += "<input type='checkbox' name='clients_browsing'>Allow to browse clients<br>";
	result += "<input type='checkbox' name='plugins_browsing'>Allow to browse plugins<br>";
	result += "<input type='checkbox' name='plugin_editing'>Allow to edit and update plugins<br>";
	result += "<input type='checkbox' name='proxy_editing'>Allow to customize proxy server<br>";
	result += "<input type='checkbox' name='contests_browsing' checked>Allow to browse contests<br>";
	result += "<input type='checkbox' name='contest_editing'>Allow to edit contests<br>";
	result += "<input type='checkbox' name='contest_watching'>Allow to watch contests<br>";
	result += "<input type='checkbox' name='contest_starting' checked>Allow to start virtual contests<br>";
	result += "<input type='checkbox' name='bot'>Bot<br>";
	result += "<input type='checkbox' name='manage'>Allow to manage server.<br>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Add'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string EditContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_DENIED )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contestant_id;
	if( !GetVariable( parameter, "contestant_id", contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contestant_id'." );
	// Чтение из базы
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contestant_id, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	// Ещё одна проверка прав доступа к странице
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_HIMSELF && client_data.ContestantId != contestant_id )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/edit_contestant.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' value='%lu' name='contestant_id'>", contestant_data.Key );
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Login:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='login' maxlength='%lu' value='%s'>", MAX_LOGIN_LENGTH, Escape( contestant_data.Login ).c_str() );
	result += "</td>";
	result += "</tr>";
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) != STATUS_CONTESTANT_EDITING_FULL )
	{
		result += "<tr>";
		result += "<td class='edit_field_name'>Old password (type only if you want to change it):</td>";
		result += "<td class='edit_field_value'>";
		result += StringPrintf( "<input class='text' type='password' name='old_password' maxlength='%lu' value=''>", MAX_PASSWORD_LENGTH );
		result += "</td>";
		result += "</tr>";
	}
	result += "<tr>";
	result += "<td class='edit_field_name'>New password:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='password' name='new_password' maxlength='%lu' value=''>", MAX_PASSWORD_LENGTH );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Confirmation:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='password' name='confirmation' maxlength='%lu' value=''>", MAX_PASSWORD_LENGTH );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Name:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='name' maxlength='%lu' value='%s'>", nsContestantDataBase::MAX_NAME_LENGTH, Escape( contestant_data.Name ).c_str() );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Comment:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<textarea class='text' name='comment' rows='4'>%s</textarea>", Escape( contestant_data.Comment ).c_str() );
	result += "</td>";
	result += "</tr>";
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_FULL )
	{
		result += "<tr>";
		result += "<td class='edit_field_name'>Status:</td>";
		result += "<td class='edit_field_value'>";
		result += StringPrintf( "<input type='checkbox' name='contestants_browsing' %s>Allow to browse contestants<br>", contestant_data.Status & STATUS_CONTESTANTS_BROWSING ? "checked" : "" );
		result += StringPrintf( "<input type='radio' name='contestant_editing' value='0' %s>Don't allow to edit contestants<br>", ( contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_DENIED ? "checked" : "" );
		result += StringPrintf( "<input type='radio' name='contestant_editing' value='1' %s>Allow to edit himself only<br>", ( contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_HIMSELF ? "checked" : "" );
		result += StringPrintf( "<input type='radio' name='contestant_editing' value='2' %s>Allow to edit everyone, but don't allow to edit access rights<br>", ( contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_BASIC ? "checked" : "" );
		result += StringPrintf( "<input type='radio' name='contestant_editing' value='3' %s>Allow to edit everyone and everything<br>", ( contestant_data.Status & STATUS_CONTESTANT_EDITING ) == STATUS_CONTESTANT_EDITING_FULL ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='clients_browsing' %s>Allow to browse clients<br>", contestant_data.Status & STATUS_CLIENTS_BROWSING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='plugins_browsing' %s>Allow to browse plugins<br>", contestant_data.Status & STATUS_PLUGINS_BROWSING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='plugin_editing' %s>Allow to edit and update plugins<br>", contestant_data.Status & STATUS_PLUGIN_EDITING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='proxy_editing' %s>Allow to customize proxy server<br>", contestant_data.Status & STATUS_PROXY_EDITING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='contests_browsing' %s>Allow to browse contests<br>", contestant_data.Status & STATUS_CONTESTS_BROWSING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='contest_editing' %s>Allow to edit contests<br>", contestant_data.Status & STATUS_CONTEST_EDITING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='contest_watching' %s>Allow to watch contests<br>", contestant_data.Status & STATUS_CONTEST_WATCHING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='contest_starting' %s>Allow to start virtual contests<br>", contestant_data.Status & STATUS_CONTEST_STARTING ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='bot' %s>Bot<br>", contestant_data.Status & STATUS_BOT ? "checked" : "" );
		result += StringPrintf( "<input type='checkbox' name='manage' %s>Allow to manage server.<br>", contestant_data.Status & STATUS_MANAGE ? "checked" : "" );
		result += "</td>";
		result += "</tr>";
	}
	result += "</table>";
	result += "<input class='submit' type='submit' value='Edit'>";
	result += "</form>"; 
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string DeleteContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( ( client_contestant_data.Status & STATUS_CONTESTANT_EDITING ) != STATUS_CONTESTANT_EDITING_FULL )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contestant_id;
	if( !GetVariable( parameter, "contestant_id", contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contestant_id'." );
	// Чтение из базы
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contestant_id, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/delete_contestant.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='delete'>";
	result += StringPrintf( "<input type='hidden' name='contestant_id' value='%lu'>", contestant_data.Key );
	result += StringPrintf( "<p class='delete'>Are you sure to delete <a class='delete' href='/contestant.html?contestant_id=%lu'>%s</a>?</p>", contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	result += "<input class='submit' type='submit' value='Confirm'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ClientsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CLIENTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<h1 class='title'>Clients</h1>";
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list'>Contestant</th>";
	result += "<th class='list'>Address</th>";
	result += "<th class='list'>Time</th>";
	result += "</tr>";
	{
		cLocker locker( *ClientDataBase );
		for( nsClientDataBase::TimeIterator client_iterator = ClientDataBase->BeginByTime(); client_iterator != ClientDataBase->EndByTime(); ++client_iterator )
		{
			if( start <= count && count < finish )
			{
				static const char *day_of_week_name[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
				static const char *month_name[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
				unsigned short year, month, day, day_of_week, hour, minute, second, millisecond;
				SplitTime( client_iterator->Time, &year, &month, &day, &day_of_week, &hour, &minute, &second, &millisecond );

				sContestantData contestant_data;

				result += "<tr class='record'>";
				if( ContestantDataBase->GetByKey( client_iterator->ContestantId, contestant_data ) )
				{
					result += "<td class='record' align='center'>";
					result += StringPrintf( "<a class='record' href='/contestant.html?contestant_id=%lu'>%s</a>", contestant_data.Key, Escape( contestant_data.Name ).c_str() );
					result += "</td>";
				}
				else
				{
					result += "<td class='record' align='center'>Guest</td>";
				}
				result += StringPrintf( "<td class='record' align='center'>%s</td>", IpAddressPort( client_iterator->Ip, client_iterator->Port ).c_str() );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<font style='font-family: arial; font-size: 13px;'>%hu:%02hu:%02hu.<font style='font-size: 10px;'>%03hu</font>&nbsp;&nbsp;&nbsp;%s,&nbsp;%hu&nbsp;%s&nbsp;%hu</font>", hour, minute, second, millisecond, day_of_week_name[ day_of_week ], day, month_name[ month - 1 ], year );
				result += "</td>";
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string PluginsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Извлечение параметров
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGINS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<h1 class='title'>Plugins</h1>";
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Title</th>";
	if( client_contestant_data.Status & STATUS_PLUGIN_EDITING )
	{
		result += "<th class='list' width='50px'>";
		result += "<a class='command' href='/add_plugin.html'><img class='command' src='/plus.png' alt='add' title='Add new plugin'></a>";
		result += "</th>";
	}
	result += "</tr>";
	{
		cLocker locker( *PluginDataBase );
		int number = 1;
		for( nsPluginDataBase::KeyIterator plugin_iterator = PluginDataBase->BeginByKey(); plugin_iterator != PluginDataBase->EndByKey(); ++plugin_iterator, ++number )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='record' href='/plugin.html?plugin_id=%lu'>%s</a>", plugin_iterator->Key, GetPluginTitle( *plugin_iterator ).c_str() );
				result += "</td>";
				if( client_contestant_data.Status & STATUS_PLUGIN_EDITING )
				{
					result += "<td class='record' align='center'>";
					result += StringPrintf( "<a class='command' href='/plugin.html?plugin_id=%lu'><img class='command' src='/info.png' alt='info' title='Info'></a>", plugin_iterator->Key );
					result += StringPrintf( "<a class='command' href='/plugin_problems.html?plugin_id=%lu'><img class='command' src='/list.png' alt='problems' title='Problems'></a>", plugin_iterator->Key );
					result += StringPrintf( "<a class='command' href='/update_plugin.html?plugin_id=%lu'><img class='command' src='/refresh.png' alt='update' title='Update plugin'></a>", plugin_iterator->Key );
					result += StringPrintf( "<a class='command' href='/configure_plugin.html?plugin_id=%lu'><img class='command' src='/pencil.png' alt='configure' title='Configure plugin'></a>", plugin_iterator->Key );
					result += StringPrintf( "<a class='command' href='/delete_plugin.html?plugin_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete plugin'></a>", plugin_iterator->Key );
					result += "</td>";
				}
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AddPluginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Извлечение параметров
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGIN_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/add_plugin.action' method='post' enctype='multipart/form-data'>";
	result += "<table cellspacing='0' align='center' width='100%'>";
	//result += "<tr>";
	//result += "<td class='edit_field_name'>Name:</td>";
	//result += "<td class='edit_field_value'>";
	//result += StringPrintf( "<input class='text' type='text' name='name' maxlength='%lu' size='50'>", nsPluginDataBase::MAX_NAME_LENGTH );
	//result += "</td>";
	//result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>File:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='file' name='plugin' size='50'>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Add'>";
	result += "</form>";	
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string PluginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGINS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long plugin_id;
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	// Чтение из базы
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<h1 class='title'>%s</h1>", GetPluginTitle( plugin_data ).c_str() );
	if( ( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) &&
		 plugin_data.Handle != NULL )
	{
		int comment_length;
		if( plugin_data.MainProc( GET_COMMENT_LENGTH, 0, &comment_length ) )
		{
			cMemory< char > comment( comment_length + 1 );
			if( plugin_data.MainProc( GET_COMMENT, 0, comment ) )
			{
				result += "<hr>";
				result += StringPrintf( "<h2 class='comment'>%s</h2>", ( char * )comment );
			}
		}
	}
	if( client_contestant_data.Status & STATUS_PLUGIN_EDITING )
	{
		result += "<hr>";
		result += "<form action='/enable_plugin.action' method='post' enctype='application/x-www-form-urlencoded'>";
		result += StringPrintf( "<input type='hidden' name='plugin_id' value='%lu'>", plugin_id );
		result += StringPrintf( "<input type='hidden' name='is_enabled' value='%lu'>", ( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) ? 0ul : 1ul );
		result += StringPrintf( "<input class='submit' type='submit' value='%s'>", ( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) ? "Disable" : "Enable" );
		result += "</form>";
		result += "<hr>";
		result += StringPrintf( "<a class='record' href='/plugin_problems.html?plugin_id=%lu'>Problems</a><br>", plugin_id );
		result += StringPrintf( "<a class='record' href='/update_plugin.html?plugin_id=%lu'>Update</a><br>", plugin_id );
		result += StringPrintf( "<a class='record' href='/configure_plugin.html?plugin_id=%lu'>Configure</a><br>", plugin_id );
		result += StringPrintf( "<a class='record' href='/delete_plugin.html?plugin_id=%lu'>Delete</a>", plugin_id );
	}
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string PluginProblemsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGINS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long plugin_id;
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/plugin.html?plugin_id=%lu'><h1 class='title'>%s</h1></a>", plugin_data.Key, GetPluginTitle( plugin_data ).c_str() );
	result += "<hr>";
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Title</th>";
	result += "<th class='list' width='50px'>&nbsp;</th>";
	result += "</tr>";
	if( ( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) && plugin_data.Handle != NULL )
	{
		if( !RefreshProblems( plugin_id ) )
			return ErrorHtml( client_data, "SelectProblemHtml::RefreshProblems returned false." );
		cLocker locker( *ProblemDataBase );
		for( nsProblemDataBase::PluginIdIterator problem_iterator = ProblemDataBase->LowerBoundByPluginId( plugin_id ), problem_end = ProblemDataBase->UpperBoundByPluginId( plugin_id ); problem_iterator != problem_end; ++problem_iterator )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%lu.</td>", problem_iterator->Index );
				result += StringPrintf( "<td class='record' align='center'><a class='record' href='/problem.html?problem_id=%lu'>%s</a></td>", problem_iterator->Key, problem_iterator->Header );
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string UpdatePluginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGIN_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long plugin_id;
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	// Чтение из базы
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<h1 class='title'>%s</h1>", GetPluginTitle( plugin_data ).c_str() );
	result += "<hr>";
	result += "<form action='/update_plugin.action' method='post' enctype='multipart/form-data'>";
	result += StringPrintf( "<input type='hidden' name='plugin_id' value='%lu'>", plugin_id );
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>File:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='file' name='plugin' size='50'>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Update'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ConfigurePluginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGIN_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long plugin_id;
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	// Чтение из базы
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<h1 class='title'>%s</h1>", GetPluginTitle( plugin_data ).c_str() );
	result += "<hr>";
	result += "<form action='/configure_plugin.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='plugin_id' value='%lu'>", plugin_id );
	result += "<table class='edit' cellspacing='0' align='center'>";
	if( ( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) && plugin_data.Handle != NULL )
	{
		unsigned long variables_count;
		if( !plugin_data.MainProc( GET_VARIABLES_COUNT, 0, &variables_count ) )
			return ErrorHtml( client_data, "ConfigurePluginHtml::plugin_data.MainProc(GET_VARIABLES_COUNT) returned false." );
		for( unsigned long variable_id = 0; variable_id < variables_count; ++variable_id )
		{
			unsigned long variable_properties_length;
			if( !plugin_data.MainProc( GET_VARIABLE_PROPERTIES_LENGTH, variable_id, &variable_properties_length ) )
			{
				unsigned long variable_name_length;
				if( !plugin_data.MainProc( GET_VARIABLE_NAME_LENGTH, variable_id, &variable_name_length ) )
					return ErrorHtml( client_data, "ConfigurePluginHtml::plugin_data.MainProc(GET_VARIABLE_NAME_LENGTH) returned false." );
				cMemory< char > variable_name( variable_name_length + 1 );
				if( !plugin_data.MainProc( GET_VARIABLE_NAME, variable_id, variable_name ) )
					return ErrorHtml( client_data, "ConfigurePluginHtml::plugin_data.MainProc(GET_VARIABLE_NAME) returned false." );
				string variable_value;
				{
					cLocker locker( ConfigCriticalSection );
					variable_value = Config[ "Plugins" ][ plugin_data.Name ][ variable_name ];
				}
				result += "<tr>";
				result += StringPrintf( "<td class='edit_field_name'>%s:</td>", ( char * )variable_name );
				result += "<td class='edit_field_value'>";
				result += StringPrintf( "<input class='text' type='text' name='%s' size='16' value='%s'>", ( char * )variable_name, variable_value.c_str() );
				result += "</td>";
				result += "</tr>";
				continue;
			}
			cMemory< char > variable_properties( variable_properties_length + 1 );
			if( !plugin_data.MainProc( GET_VARIABLE_PROPERTIES, variable_id, variable_properties ) )
				return ErrorHtml( client_data, "ConfigurePluginHtml::plugin_data.MainProc(GET_VARIABLE_PROPERTIES) returned false." );
			cFormat variable;
			if( !variable.CreateFromString( string( variable_properties ) ) )
				return ErrorHtml( client_data, "ConfigurePluginHtml::variable.CreateFromString returned false." );
			string variable_value;
			{
				cLocker locker( ConfigCriticalSection );
				variable_value = Config[ "Plugins" ][ plugin_data.Name ][ variable[ "Name" ] ];
			}
			result += "<tr>";
			result += StringPrintf( "<td class='edit_field_name'>%s:</td>", variable[ "Name" ].AsString().c_str() );
			result += "<td class='edit_field_value'>";
			if( variable.Find( "Option" ) != variable.End() )
			{
				result += StringPrintf( "<select class='text' name='%s'>", variable[ "Name" ].AsString().c_str() );
				result += "<option></option>";
				for( int option_index = 0, option_size = variable[ "Option" ].Size(); option_index != option_size; ++option_index )
				{
					result += StringPrintf( "<option value='%s' %s>%s</option>", variable[ "Option" ][ option_index ][ "Value" ].AsString().c_str(), variable[ "Option" ][ option_index ][ "Value" ].AsString() == variable_value ? "selected" : "", variable[ "Option" ][ option_index ][ "Title" ].AsString().c_str() );
				}
				result += "</select>";
			}
			else
			{
				result += StringPrintf( "<input class='text' type='text' name='%s' size='16' value='%s'>", variable[ "Name" ].AsString().c_str(), variable_value.c_str() );
			}
			result += "</td>";
			result += "</tr>";
		}
	}
	result += "</table>";
	result += "<input class='submit' type='submit' value='Edit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string DeletePluginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PLUGIN_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long plugin_id;
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	// Чтение из базы
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/delete_plugin.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='delete'>";
	result += StringPrintf( "<input type='hidden' name='plugin_id' value='%lu'>", plugin_id );
	result += StringPrintf( "<p class='delete'>Are you sure to delete <a class='delete' href='/plugin.html?plugin_id=%lu'>%s</a>?</p>", plugin_id, GetPluginTitle( plugin_data ).c_str() );
	result += "<input class='submit' type='submit' value='Confirm'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ProxyHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_PROXY_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<h1 class='title'>Proxy settings</h1>";
	result += "<form action='/proxy.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>State:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_proxy_used'>"; 
	result += StringPrintf( "<option value='1' %s>Enabled</option>", IsRemoteProxyUsed ? "selected" : "" );
	result += StringPrintf( "<option value='0' %s>Disabled</option>", IsRemoteProxyUsed ? "" : "selected" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Host:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='proxy_host' value='%s' size='50'>", ( ( string )( RemoteProxyHost ) ).c_str() );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Port:</td>";
	result += "<td class='edit_fiend_value'>";
	result += StringPrintf( "<input class='text' type='text' name='proxy_port' value='%hu'>", ( unsigned short )RemoteProxyPort );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Login:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='proxy_login' value='%s' size='50'>", ( ( string )( RemoteProxyLogin ) ).c_str() );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>New password:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='password' name='proxy_password' value='' size='50'>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Confirmation:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='password' name='proxy_confirmation' value='' size='50'>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Submit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<h1 class='title'>Contests</h1>";
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>&nbsp;</th>";
	result += "<th class='list'>Title</th>";
	result += "<th class='list' width='50px'>Duration</th>";
	if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
	{
		result += "<th class='list' width='50px'>";
		result += "<a class='command' href='/add_contest.html'><img class='command' src='/plus.png' alt='add' title='Add new contest'></a>";
		result += "<a class='command' href='/upload_contest.html'><img class='command' src='/diskette.png' alt='upload' title='Upload contest'></a>";
		result += "</th>";
	}
	result += "</tr>";
	{
		cLocker locker( *ContestDataBase );
		int number = 1;
		for( TitleIterator contest_iterator = ContestDataBase->BeginByTitle(); contest_iterator != ContestDataBase->EndByTitle(); ++contest_iterator, ++number )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += "<td class='record' align='right'>";
				//if( contest_iterator->IsEnabled )
				if( ( contest_iterator->Flags & nsContestDataBase::FLAG_ENABLED ) )
					result += "<img class='command' src='/green_shield.png' alt='Enabled' title='Contest is enabled'>";
				else
					result += "<img class='command' src='/red_shield.png' alt='Disabled' title='Contest is disabled'>";
				result += "</td>";
				result += StringPrintf( "<td class='record' align='center'><a class='record' href='contest.html?contest_id=%lu'>%s</a></td>", contest_iterator->Key, contest_iterator->Title );
				result += StringPrintf( "<td class='record' align='right'>%lu:%02lu</td>", contest_iterator->Duration / 60 / 60, contest_iterator->Duration / 60 % 60 );
				if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
				{
					result += "<td class='record' align='center'>";
					result += StringPrintf( "<a class='command' href='/edit_contest.html?contest_id=%lu'><img class='command' src='pencil.png' alt='edit' title='Edit contest'></a>", contest_iterator->Key );
					result += StringPrintf( "<a class='command' href='/delete_contest.html?contest_id=%lu'><img class='command' src='cross.png' alt='delete' title='Delete contest'></a>", contest_iterator->Key );
					result += "</td>";
				}
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	sContestContestantData contest_contestant_data;
	bool is_contest_started = ContestContestantDataBase->GetByContestContestant( contest_id, client_data.ContestantId, contest_contestant_data );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<h1 class='title'>%s</h1>", Escape( contest_data.Title ).c_str() );
	if( *contest_data.Comment != '\0' )
	{
		result += "<hr>";
		result += StringPrintf( "<h2 class='comment'>%s</h2>", Escape( contest_data.Comment ).c_str() );
	}
	if( is_contest_started )
	{
		unsigned short year, month, day, day_of_week, hour, minute, second, millisecond;
		unsigned long long start_time = contest_contestant_data.StartTime;
		unsigned long long finish_time = contest_contestant_data.StartTime + ( unsigned long long )( contest_data.Duration + contest_contestant_data.AdditionTime ) * 10000000;
		unsigned long long current_time = client_data.Time;
		long elapsed_time = ( long )( ( long long )( current_time - start_time ) / 10000000 );
		long remaining_time = ( long )( ( long long )( finish_time - current_time ) / 10000000 );
		result += "<hr>";
		result += "<table cellspacing='0' align='center'>";
		result += "<tr>";
		result += "<td class='variable_name'>Start time</td>";
		result += "<td class='variable_value'>";
		SplitTime( start_time, &year, &month, &day, &day_of_week, &hour, &minute, &second, &millisecond );
		result += StringPrintf( "%hu:%02hu:%02hu&nbsp;&nbsp;&nbsp;%s,&nbsp;%hu&nbsp;%s&nbsp;%hu", hour, minute, second, DayOfWeekName[ day_of_week ], day, MonthName[ month - 1 ], year );
		result += "</td>";
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Finish time</td>";
		result += "<td class='variable_value'>";
		SplitTime( finish_time, &year, &month, &day, &day_of_week, &hour, &minute, &second, &millisecond );
		result += StringPrintf( "%hu:%02hu:%02hu&nbsp;&nbsp;&nbsp;%s,&nbsp;%hu&nbsp;%s&nbsp;%hu", hour, minute, second, DayOfWeekName[ day_of_week ], day, MonthName[ month - 1 ], year );
		result += "</td>";
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Current time</td>";
		result += "<td class='variable_value'>";
		SplitTime( current_time, &year, &month, &day, &day_of_week, &hour, &minute, &second, &millisecond );
		result += StringPrintf( "%hu:%02hu:%02hu&nbsp;&nbsp;&nbsp;%s,&nbsp;%hu&nbsp;%s&nbsp;%hu", hour, minute, second, DayOfWeekName[ day_of_week ], day, MonthName[ month - 1 ], year );
		result += "</td>";
		result += "</tr>";
		if( elapsed_time < 0 )
		{
			result += "<tr>";
			result += "<td class='variable_name'>State</td>";
			result += "<td class='variable_value'>Not started</td>";
			result += "</tr>";
			result += "<tr>";
			result += "<td class='variable_name'>Starts in</td>";
			result += "<td class='variable_value'>";
			result += StringPrintf( "%hu:%02hu:%02hu", -elapsed_time / 60 / 60, -elapsed_time / 60 % 60, -elapsed_time % 60 );
			result += "</td>";
			result += "</tr>";
		}
		else if( remaining_time < 0 )
		{
			result += "<tr>";
			result += "<td class='variable_name'>State</td>";
			result += "<td class='variable_value'>Finished</td>";
			result += "</tr>";
		}
		else
		{
			result += "<tr>";
			result += "<td class='variable_name'>State</td>";
			result += "<td class='variable_value'>In progress</td>";
			result += "</tr>";
			result += "<tr>";
			result += "<td class='variable_name'>Elapsed time</td>";
			result += "<td class='variable_value'>";
			result += StringPrintf( "%hu:%02hu:%02hu", elapsed_time / 60 / 60, elapsed_time / 60 % 60, elapsed_time % 60 );
			result += "</td>";
			result += "</tr>";
			result += "<tr>";
			result += "<td class='variable_name'>Remaining time</td>";
			result += "<td class='variable_value'>";
			result += StringPrintf( "%hu:%02hu:%02hu", remaining_time / 60 / 60, remaining_time / 60 % 60, remaining_time % 60 );
			result += "</td>";
			result += "</tr>";
		}
		result += "</table>";
	}
	//else if( client_contestant_data.Status & STATUS_CONTEST_STARTING && contest_data.IsEnabled )
	else if( client_contestant_data.Status & STATUS_CONTEST_STARTING && ( contest_data.Flags & nsContestDataBase::FLAG_ENABLED ) )
	{
		result += "<hr>";
		result += "<center>";
		result += "<form action='/start_contest.action' method='post' enctype='application/x-www-form-urlencoded' style='margin: 0px; padding: 0px;'>";
		result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
		result += "<input type='submit' class='submit' value='Start'>";
		result += "</form>";
		result += "</center>";
	}
	
	if( is_contest_started && contest_contestant_data.StartTime <= client_data.Time )
	{
		result += "<hr>";
		result += "<table align='center' width='100%' cellspacing='0'>";
		result += "<tr>";
		result += "<th class='list' width='25px'>#</th>";
		result += "<th class='list'>Header</th>";
		result += "<th class='list' width='50px'>&nbsp;</th>";
		result += "</tr>";
		{
			cLocker problem_locker( *ProblemDataBase );
			cLocker contest_problem_locker( *ContestProblemDataBase );
			for( nsContestProblemDataBase::ContestIdIterator contest_problem_iterator = ContestProblemDataBase->LowerBoundByContestId( contest_id ), contest_problem_end = ContestProblemDataBase->UpperBoundByContestId( contest_id ); contest_problem_iterator != contest_problem_end; ++contest_problem_iterator )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%s.</td>", contest_problem_iterator->Letter );
//				result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s</a></td>", contest_problem_iterator->Key, problem_data.Header );
				sProblemData problem_data;
				if( ProblemDataBase->GetByKey( contest_problem_iterator->ProblemId, problem_data ) )
					result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s</a></td>", contest_problem_iterator->Key, problem_data.Header );
				else
					result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem.html?contest_problem_id=%lu'><font class='error'>Error</font></a></td>", contest_problem_iterator->Key );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='command' href='/submit.html?contest_contestant_id=%lu&contest_problem_id=%lu'>submit</a>", contest_contestant_data.Key, contest_problem_iterator->Key );
				result += "</td>";
				result += "</tr>";
			}
		}
		result += "</table>";
	}
	if( is_contest_started )
	{
		result += "<hr>";
		result += StringPrintf( "<a class='record' href='/monitor.html?contest_contestant_id=%lu'>Monitor</a><br>", contest_contestant_data.Key );
		result += StringPrintf( "<a class='record' href='/contest_contestant_problems.html?contest_contestant_id=%lu'>Submits</a><br>", contest_contestant_data.Key );
	}
	if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
	{
		result += "<hr>";
		result += "<table cellspacing='0' align='center'>";
		result += "<tr>";
		result += "<td class='variable_name'>Accessibility</td>";
		result += StringPrintf( "<td class='variable_value'>%s</td>", contest_data.Flags & nsContestDataBase::FLAG_ENABLED ? "Enabled" : "Disabled" );
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Duration</td>";
		result += StringPrintf( "<td class='variable_value'>%lu:%02lu</td>", contest_data.Duration / 60 / 60, contest_data.Duration / 60 % 60 );
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Frozen</td>";
		result += StringPrintf( "<td class='variable_value'>%s</td>", contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED ? "Enabled" : "Disabled" );
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Frozen time</td>";
		result += StringPrintf( "<td class='variable_value'>%lu:%02lu</td>", contest_data.FrozenTime / 60 / 60, contest_data.FrozenTime / 60 % 60 );
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Penalty</td>";
		result += StringPrintf( "<td class='variable_value'>%lu</td>", contest_data.Penalty );
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>ITMO rating</td>";
		result += StringPrintf( "<td class='variable_value'>%s</td>", contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING ? "Enabled" : "Disabled" );
		result += "</tr>";
		result += "<tr>";
		result += "<td class='variable_name'>Aftersubmit</td>";
		result += StringPrintf( "<td class='variable_value'>%s</td>", contest_data.Flags & nsContestDataBase::FLAG_AFTERSUBMIT ? "Enabled" : "Disabled" );
		result += "</tr>";
		result += "</table>";
		result += "<hr>";
		result += StringPrintf( "<a class='record' href='/contest_contestants.html?contest_id=%lu'>Contestants</a><br>", contest_id );
		result += StringPrintf( "<a class='record' href='/contest_problems.html?contest_id=%lu'>Problems</a><br>", contest_id );
		result += StringPrintf( "<a class='record' href='/edit_contest.html?contest_id=%lu'>Edit</a><br>", contest_id );
		result += StringPrintf( "<a class='record' href='/delete_contest.html?contest_id=%lu'>Delete</a>", contest_id );
		result += "<hr>";
		result += "<form action='/add_submits.action' method='post' enctype='multipart/form-data'>";
		result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
		result += "<table class='edit' cellspacing='0' align='center'>";
		result += "<tr>";
		result += "<td class='edit_field_name'>File of submits:</td>";
		result += "<td class='edit_field_value'><input class='file' type='file' name='file' size='50'></td>";
		result += "</tr>";
		result += "</table>";
		result += "<input type='submit' class='submit' value='Add'>";
		result += "</form>";
		result += "<hr>";
		result += "<center>";
		result += StringPrintf( "<a class='record' href='/contest.txt?contest_id=%lu'>Download as text</a>", contest_id );
		result += "</center>";
	}
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AddContestHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/add_contest.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<table class='edit' cellspacing='0' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Title:</td>";
	result += StringPrintf( "<td class='edit_field_value'><input class='text' type='text' name='title' value='' size='50' maxlength='%lu'></td>", nsContestDataBase::MAX_TITLE_LENGTH );
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Comment:</td>";
	result += StringPrintf( "<td class='edit_field_value'><input class='text' type='text' name='comment' value='' size='50' maxlength='%lu'></td>", nsContestDataBase::MAX_COMMENT_LENGTH );
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Duration:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='text' name='duration_hour' value='' size='3' maxlength='4'>:<input class='text' type='text' name='duration_minute' value='' size='3' maxlength='2'>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Accessibility:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_enabled'>";
	result += "<option value='1'>Enabled</option>";
	result += "<option value='0' selected>Disabled</option>";
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Frozen</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_frozen_enabled'>";
	result += "<option value='1' selected>Enabled</option>";
	result += "<option value='0'>Disabled</option>";
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Frozen time</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='text' name='frozen_time_hour' value='' size='3'>:<input class='text' type='text' name='frozen_time_minute' value='' size='3'>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Penalty:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input class='text' type='text' name='penalty' value='20' size='5' maxlength='5'>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>ITMO rating</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_itmo_rating_enabled'>";
	result += "<option value='1'>Enabled</option>";
	result += "<option value='0' selected>Disabled</option>";
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Aftersubmit</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_aftersubmit_enabled'>";
	result += "<option value='1' selected>Enabled</option>";
	result += "<option value='0'>Disabled</option>";
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input type='submit' class='submit' value='Add'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string EditContestHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/edit_contest.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
	result += "<table class='edit' cellspacing='0' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Title:</td>";
	result += StringPrintf( "<td class='edit_field_value'><input class='text' type='text' name='title' value='%s' size='50' maxlength='%lu'></td>", Escape( contest_data.Title ).c_str(), nsContestDataBase::MAX_TITLE_LENGTH );
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Comment:</td>";
	result += StringPrintf( "<td class='edit_field_value'><input class='text' type='text' name='comment' value='%s' size='50' maxlength='%lu'></td>", Escape( contest_data.Comment ).c_str(), nsContestDataBase::MAX_COMMENT_LENGTH );
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Duration:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='duration_hour' value='%lu' size='3' maxlength='4'>:<input class='text' type='text' name='duration_minute' value='%02lu' size='3' maxlength='2'>", contest_data.Duration / 60 / 60, contest_data.Duration / 60 % 60 );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Accessibility:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_enabled'>";
	//result += StringPrintf( "<option value='1' %s>Enabled</option>", contest_data.IsEnabled ? "selected" : "" );
	result += StringPrintf( "<option value='1' %s>Enabled</option>", contest_data.Flags & nsContestDataBase::FLAG_ENABLED ? "selected" : "" );
	//result += StringPrintf( "<option value='0' %s>Disabled</option>", contest_data.IsEnabled ? "" : "selected" );
	result += StringPrintf( "<option value='0' %s>Disabled</option>", contest_data.Flags & nsContestDataBase::FLAG_ENABLED ? "" : "selected" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Frozen</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_frozen_enabled'>";
	//result += StringPrintf( "<option value='1' %s>Enabled</option>", contest_data.IsFrozenEnabled ? "selected" : "" );
	result += StringPrintf( "<option value='1' %s>Enabled</option>", contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED ? "selected" : "" );
	//result += StringPrintf( "<option value='0' %s>Disabled</option>", contest_data.IsFrozenEnabled ? "" : "selected" );
	result += StringPrintf( "<option value='0' %s>Disabled</option>", contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED ? "" : "selected" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Frozen time</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='frozen_time_hour' value='%lu' size='3' maxlength='4'>:<input class='text' type='text' name='frozen_time_minute' value='%02lu' size='3' maxlength='2'>", contest_data.FrozenTime / 60 / 60, contest_data.FrozenTime / 60 % 60 );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Penalty:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='penalty' value='%lu' size='5' maxlength='5'>", contest_data.Penalty );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>ITMO rating</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_itmo_rating_enabled'>";
	result += StringPrintf( "<option value='1' %s>Enabled</option>", contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING ? "selected" : "" );
	result += StringPrintf( "<option value='0' %s>Disabled</option>", contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING ? "" : "selected" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Aftersubmit</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='is_aftersubmit_enabled'>";
	result += StringPrintf( "<option value='1' %s>Enabled</option>", contest_data.Flags & nsContestDataBase::FLAG_AFTERSUBMIT ? "selected" : "" );
	result += StringPrintf( "<option value='0' %s>Disabled</option>", contest_data.Flags & nsContestDataBase::FLAG_AFTERSUBMIT ? "" : "selected" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input type='submit' class='submit' value='Edit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string DeleteContestHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/delete_contest.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='delete'>";
	result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
	result += StringPrintf( "<p class='delete'>Are you sure to delete <a class='delete' href='/contest.html?contest_id=%lu'>%s</a>?</p>", contest_id, Escape( contest_data.Title ).c_str() );
	result += "<input class='submit' type='submit' value='Confirm'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestProblemsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Header</th>";
	result += "<th class='list' width='50px'>";
	result += StringPrintf( "<a class='command' href='/add_contest_problem.html?contest_id=%lu'><img class='command' src='/plus.png' alt='add' title='Add problem into contest'></a>", contest_id );
	result += "</th>";
	result += "</tr>";
	{
		cLocker problem_locker( *ProblemDataBase ); // База problem должна быть залокана до contest_problem
		cLocker contest_problem_locker( *ContestProblemDataBase );
		for( nsContestProblemDataBase::ContestIdIterator contest_problem_iterator = ContestProblemDataBase->LowerBoundByContestId( contest_id ), contest_problem_end = ContestProblemDataBase->UpperBoundByContestId( contest_id ); contest_problem_iterator != contest_problem_end; ++contest_problem_iterator )
		{
			sProblemData problem_data;
			if( !ProblemDataBase->GetByKey( contest_problem_iterator->ProblemId, problem_data ) )
				return ErrorHtml( client_data, "Problem doesn't exist." );
			result += "<tr>";
			result += StringPrintf( "<td class='record' align='right'>%s.</td>", contest_problem_iterator->Letter );
			result += StringPrintf( "<td class='record' align='center'><a class='record' href='/problem.html?problem_id=%lu'>%s</a></td>", problem_data.Key, problem_data.Header );
			result += "<td class='record' align='center'>";
			result += StringPrintf( "<a class='command' href='/rejudge_problem.action?contest_problem_id=%lu'><img class='command' src='/refresh.png' alt='rejudge' title='Rejudge problem'></a>", contest_problem_iterator->Key );
			result += StringPrintf( "<a class='command' href='/contest_problem_contestants.html?contest_problem_id=%lu'><img class='command' src='/list.png' alt='submits' title='View submits'></a>", contest_problem_iterator->Key );
			result += StringPrintf( "<a class='command' href='/edit_contest_problem.html?contest_problem_id=%lu'><img class='command' src='/pencil.png' alt='edit' title='Edit problem'></a>", contest_problem_iterator->Key );
			result += StringPrintf( "<a class='command' href='/delete_contest_problem.html?contest_problem_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete problem from contest'></a>", contest_problem_iterator->Key );
			result += "</td>";
			result += "</tr>";
		}
	}
	result += "</table>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AddContestProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	unsigned long problem_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	if( !GetVariable( parameter, "problem_id", problem_id ) )
		problem_id = BAD_KEY;
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	if( problem_id != BAD_KEY )
	{
		sProblemData problem_data;
		if( !ProblemDataBase->GetByKey( problem_id, problem_data ) )
			return ErrorHtml( client_data, "Not found" );
		result += StringPrintf( "<a class='record' href='problem.html?problem_id=%lu'>%s</a><br>", problem_id, problem_data.Header );
	}
	result += StringPrintf( "<a class='command' href='select_plugin.html?contest_id=%lu'>select/change</a>", contest_id );
	result += "<hr>";
	result += "<form action='/add_contest_problem.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
	if( problem_id != BAD_KEY )
		result += StringPrintf( "<input type='hidden' name='problem_id' value='%lu'>", problem_id );
	result += "<table class='edit' cellspacing='0'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Letter:</td>";
	result += StringPrintf( "<td class='edit_field_value'><input class='text' name='letter' value='' size='16' maxlength='%lu'></td>", MAX_LETTER_LENGTH );
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Add'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string SelectPluginHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Title</th>";
	result += "<th class='list' width='50px'>&nbsp;</th>";
	result += "</tr>";
	{
		cLocker locker( *PluginDataBase );
		int number = 1;
		for( nsPluginDataBase::NameIterator plugin_iterator = PluginDataBase->BeginByName(); plugin_iterator != PluginDataBase->EndByName(); ++plugin_iterator, ++number )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				result += StringPrintf( "<td class='record' align='center'><a class='record' href='/select_problem.html?contest_id=%lu&plugin_id=%lu'>%s</a></td>", contest_id, plugin_iterator->Key, GetPluginTitle( *plugin_iterator ).c_str() );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='command' href='/select_problem.html?contest_id=%lu&plugin_id=%lu'><img class='command' src='/mark.png' alt='select' title='Select plugin'></a>", contest_id, plugin_iterator->Key );
				result += StringPrintf( "<a class='command' href='/plugin.html?plugin_id=%lu'><img class='command' src='/info.png' alt='info' title='Plugin info'></a>", plugin_iterator->Key );
				result += "</td>";
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string SelectProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	unsigned long plugin_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<a class='record' href='/plugin.html?plugin_id=%lu'>%s</a>", plugin_data.Key, GetPluginTitle( plugin_data ).c_str() );
	result += "<hr>";
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Title</th>";
	result += "<th class='list' width='50px'>&nbsp;</th>";
	result += "</tr>";
	if( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED && plugin_data.Handle != NULL )
	{
		if( !RefreshProblems( plugin_id ) )
			return ErrorHtml( client_data, "SelectProblemHtml::RefreshProblems returned false." );
		cLocker locker( *ProblemDataBase );
		for( nsProblemDataBase::PluginIdIterator problem_iterator = ProblemDataBase->LowerBoundByPluginId( plugin_id ), problem_end = ProblemDataBase->UpperBoundByPluginId( plugin_id ); problem_iterator != problem_end; ++problem_iterator )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%lu.</td>", problem_iterator->Index );
				result += StringPrintf( "<td class='record' align='center'><a class='record' href='/problem.html?problem_id=%lu'>%s</a></td>", problem_iterator->Key, problem_iterator->Header );
				result += StringPrintf( "<td class='record' align='center'><a class='command' href='/add_contest_problem.html?contest_id=%lu&problem_id=%lu'>select</a></td>", contest_id, problem_iterator->Key );
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string EditContestProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
	// Чтение из базы
	sContestProblemData contest_problem_data;
	if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_problem_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<a class='record' href='problem.html?problem_id=%lu'>%s</a><br>", problem_data.Key, problem_data.Header );
	result += "<hr>";
	result += "<form action='/edit_contest_problem.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_problem_id' value='%lu'>", contest_problem_id );
	result += "<table class='edit' cellspacing='0' align='center' width='auto'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Letter:</td>";
	result += StringPrintf( "<td class='edit_field_value'><input class='text' name='letter' value='%s' size='16' maxlength='%lu'></td>", Escape( contest_problem_data.Letter ).c_str(), nsContestProblemDataBase::MAX_LETTER_LENGTH );
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Edit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string DeleteContestProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
	// Чтение из базы
	sContestProblemData contest_problem_data;
	if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/delete_contest_problem.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='delete'>";
	result += StringPrintf( "<input type='hidden' name='contest_problem_id' value='%lu'>", contest_problem_id );
	result += StringPrintf( "<p class='delete'>Are you sure to delete <a class='delete' href='/problem.html?problem_id=%lu'>%s</a> from contest?</p>", problem_data.Key, problem_data.Header );
	result += "<input class='submit' type='submit' value='Confirm'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";	
	return MainHtml( client_contestant_data, parameter, result );
}

std::string LoadProblemBody( const sClientData &client_data, const sPluginData &plugin_data, unsigned long index )
{
	unsigned long problem_body_length;
	if( !plugin_data.MainProc( GET_PROBLEM_BODY_LENGTH, index, &problem_body_length ) )
		return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_PROBLEM_BODY_LENGTH) returned false." );
	cMemory< char > problem_body( problem_body_length + 1 );
	if( !plugin_data.MainProc( GET_PROBLEM_BODY, index, problem_body ) )
		return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_PROBLEM_BODY) returned false." );
	string result( problem_body, problem_body_length );
	unsigned long additions_count;
	if( !plugin_data.MainProc( GET_PROBLEM_ADDITIONS_COUNT, index, &additions_count ) )
		return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_ADDITIONS_COUNT) returned false." );
	cMemory< unsigned long > addition_id( additions_count );
	if( !plugin_data.MainProc( GET_PROBLEM_ADDITIONS_IDS, index, addition_id ) )
		return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_ADDITIONS_IDS) returned false." );
	for( unsigned i = 0; i < additions_count; ++i )
	{
		unsigned long addition_name_length;
		if( !plugin_data.MainProc( GET_ADDITION_NAME_LENGTH, addition_id[ i ], &addition_name_length ) )
			return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_ADDITION_NAME_LENGTH) returned false." );
		cMemory< char > addition_name( addition_name_length + 1 );
		if( !plugin_data.MainProc( GET_ADDITION_NAME, addition_id[ i ], addition_name ) )
			return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_ADDITION_NAME) returned false." );
		result = Concat( Split( result, string( addition_name ) ), StringPrintf( "/addition.html?plugin_id=%lu&addition_id=%lu", plugin_data.Key, addition_id[ i ] ) );
	}
	return result;
}

std::string LoadAddition( const sClientData &client_data, const sPluginData &plugin_data, unsigned long addition_id )
{
	unsigned long addition_data_length;
	if( !plugin_data.MainProc( GET_ADDITION_DATA_LENGTH, addition_id, &addition_data_length ) )
		return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_ADDITION_DATA_LENGTH) returned false." );
	cMemory< char > addition_data( addition_data_length + 1 );
	if( !plugin_data.MainProc( GET_ADDITION_DATA, addition_id, addition_data ) )
		return ErrorHtml( client_data, "LoadProblemBody::plugin_data.MainProc(GET_ADDITION_DATA) returned false." );
	return string( addition_data, addition_data_length );
}

std::string ProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long problem_id;
	if( !GetVariable( parameter, "problem_id", problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'problem_id'." );
	// Чтение из базы
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( problem_id, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	cReadLocker locker( GetPluginCriticalSection( problem_data.PluginId ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( problem_data.PluginId, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) || plugin_data.Handle == NULL )
		return ErrorHtml( client_data, "Plugin for the problem is not accessible now." );
	return LoadProblemBody( client_data, plugin_data, problem_data.Index );
}

std::string ContestProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
	// Чтение из базы
	sContestProblemData contest_problem_data;
	if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	sContestContestantData contest_contestant_data;
	bool is_contest_started = ContestContestantDataBase->GetByContestContestant( contest_problem_data.ContestId, client_data.ContestantId, contest_contestant_data );
	// Ещё одна проверка прав
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING || is_contest_started && contest_contestant_data.StartTime <= client_data.Time ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Чтение из базы
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	cReadLocker locker( GetPluginCriticalSection( problem_data.PluginId ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( problem_data.PluginId, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) || plugin_data.Handle == NULL )
		return ErrorHtml( client_data, "Plugin for the problem is not accessible now." );
	return LoadProblemBody( client_data, plugin_data, problem_data.Index );
}

std::string ContestProblemFrameHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
	// Чтение из базы
	string result;
	result += "<center>";
	//result += StringPrintf( "<a class='record' href='/submit.html?contest_problem_id=%lu'>Submit</a>", contest_problem_id );
	//result += "<br>";
	result += StringPrintf( "<iframe width='100%%' height='100%%' frameborder='0' scrolling='auto' style='height: 100%%; ' src='/contest_problem.html?contest_problem_id=%lu'>", contest_problem_id );
	result += "</iframe>";
	result += "<br>";
	result += StringPrintf( "<a class='record' href='/submit.html?contest_problem_id=%lu'>Submit</a>", contest_problem_id );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AdditionHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long plugin_id;
	unsigned long addition_id;
	if( !GetVariable( parameter, "plugin_id", plugin_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'plugin_id'." );
	if( !GetVariable( parameter, "addition_id", addition_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'addition_id'." );
	// Чтение из базы
	cReadLocker locker( GetPluginCriticalSection( plugin_id ) );
	sPluginData plugin_data;
	if( !PluginDataBase->GetByKey( plugin_id, plugin_data ) )
		return ErrorHtml( client_data, "Plugin doesn't exist." );
	// Генерация страницы
	if( !( plugin_data.Flags & nsPluginDataBase::FLAG_ENABLED ) || plugin_data.Handle == NULL )
		return ErrorHtml( client_data, "Plugin for the problem is not accessible now." );
	return LoadAddition( client_data, plugin_data, addition_id );
}

std::string ContestContestantsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	unsigned long show_bots;
	if( !GetVariable( parameter, "show_bots", show_bots ) )
		show_bots = 0;
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<div width='100%' style='text-align: right;'><a href='/contest_contestants.html?contest_id=%lu&start=%d&finish=%d&show_bots=%d'>%s bots</a></div>", contest_id, start, finish, show_bots ? 0 : 1, show_bots ? "hide" : "show" );
	result += "<form action='/do_contest_contestant.html' method='get' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Name</th>";
	result += "<th class='list' width='80px'>";
	result += StringPrintf( "<a class='command' href='/add_contest_contestant.html?contest_id=%lu'><img class='command' src='/plus.png' alt='add' title='Add contestant into contest'></a>", contest_id );
	result += "</th>";
	result += "<th class='list' width='25px'>&nbsp;</th>";
	result += "</tr>";
	{
		cLocker contestant_locker( *ContestantDataBase );
		cLocker contest_contestant_locker( *ContestContestantDataBase );
		int number = 1;
		for( nsContestContestantDataBase::ContestIdIterator contest_contestant_iterator = ContestContestantDataBase->LowerBoundByContestId( contest_id ), contest_contestant_end = ContestContestantDataBase->UpperBoundByContestId( contest_id ); contest_contestant_iterator != contest_contestant_end; ++contest_contestant_iterator )
		{
			sContestantData contestant_data;
			bool is_contestant_exist = ContestantDataBase->GetByKey( contest_contestant_iterator->ContestantId, contestant_data );
			if( is_contestant_exist && !show_bots && contestant_data.Status & nsContestantDataBase::STATUS_BOT )
				continue;
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				if( is_contestant_exist )
					result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a></td>", contest_contestant_iterator->Key, Escape( contestant_data.Name ).c_str() );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='command' href='/monitor.html?contest_contestant_id=%lu'><img class='command' src='/tv.png' alt='monitor' title='Monitor'></a>", contest_contestant_iterator->Key );
				result += StringPrintf( "<a class='command' href='/contest_contestant_problems.html?contest_contestant_id=%lu'><img class='command' src='/list.png' alt='monitor' title='Submissions'></a>", contest_contestant_iterator->Key );
				result += StringPrintf( "<a class='command' href='/edit_contest_contestant.html?contest_contestant_id=%lu'><img class='command' src='/pencil.png' alt='edit' title='Edit contestant'></a>", contest_contestant_iterator->Key );
				result += StringPrintf( "<a class='command' href='/delete_contest_contestant.html?contest_contestant_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete contestant from contest'></a>", contest_contestant_iterator->Key );
				result += "</td>";
				result += StringPrintf( "<td class='record' width='25px'><input type='checkbox' name='contest_contestant_id' value='%lu'></td>", contest_contestant_iterator->Key );
				result += "</tr>";
			}
			++count;
			++number;
		}
	}
	result += "</table>";
	result += "<div align='right'>";
	result += "<input class='text' type='submit' name='action' value='Edit'>";
	// Надо это будет доделать ещё
	result += "&nbsp;&nbsp;&nbsp;";
	result += "<input class='text' type='submit' name='action' value='Delete'>";
	result += "</div>";
	result += "</form>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AddContestContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	vector< unsigned long > contestant_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "Thist page requires integer variable 'contest_id'." );
	if( !GetVariable( parameter, "contestant_id", contestant_id ) )
		contestant_id.clear();
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	for( int i = 0; i < ( int )contestant_id.size(); ++i )
	{
		sContestantData contestant_data;
		if( ContestantDataBase->GetByKey( contestant_id[ i ], contestant_data ) )
			result += StringPrintf( "<a class='record' href='contestant.html?contestant_id=%lu'>%s</a><br>", contestant_id[ i ], Escape( contestant_data.Name ).c_str() );
		else
			result += StringPrintf( "<a class='record' href='contestant.html?contestant_id=%lu'><font class='error'>Error</font></a><br>", contestant_id[ i ], Escape( contestant_data.Name ).c_str() );
	}
	result += StringPrintf( "<a class='command' href='select_contestant.html?contest_id=%lu'>select/change</a>", contest_id );
	result += "<hr>";
	result += "<form action='/add_contest_contestant.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
	for( int i = 0; i < ( int )contestant_id.size(); ++i )
	{
		result += StringPrintf( "<input type='hidden' name='contestant_id' value='%lu'>", contestant_id[ i ] );
	}
	result += "<table class='edit' cellspacing='0'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Start time:</td>";
	unsigned short hour, minute, second, day, month, year;
	SplitTime( client_data.Time, &year, &month, &day, NULL, &hour, &minute, &second, NULL );
	result += StringPrintf( "<td class='edit_field_value'><input type='text' class='text' name='start_time_hour' value='%hu' size='2' maxlength='2'><b>:</b><input class='text' type='text' name='start_time_minute' value='%02hu' size='2' maxlength='2'><b>:</b><input class='text' type='text' name='start_time_second' value='%02hu' size='2' maxlength='2'> <input type='text' class='text' name='start_time_day' value='%02hu' size='2' maxlength='2'><b>.</b><input type='text' class='text' name='start_time_month' value='%02hu' size='2' maxlength='2'><b>.</b><input class='text' type='text' name='start_time_year' value='%04hu' maxlength='4' size='4'></td>", hour, minute, second, day, month, year );
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Visibility level:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='visibility_level'>";
	result += StringPrintf( "<option value='%ld'>Blind</option>", VISIBILITY_LEVEL_BLIND );
	result += StringPrintf( "<option value='%ld' selected>Onsite</option>", VISIBILITY_LEVEL_ONSITE );
	result += StringPrintf( "<option value='%ld'>Virtual</option>", VISIBILITY_LEVEL_VIRTUAL );
	result += StringPrintf( "<option value='%ld'>Admin</option>", VISIBILITY_LEVEL_ADMIN );
	result += StringPrintf( "<option value='%ld'>God</option>", VISIBILITY_LEVEL_GOD );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Addition time:</td>";
	result += "<td class='edit_field_value'><input type='text' class='text' name='addition_time_hour' value='0' size='4' maxlength='4'><b>:</b><input type='text' class='text' name='addition_time_minute' value='0' size='2' maxlength='2'><b>:</b><input type='text' class='text' name='addition_time_second' value='0' size='2' maxlength='2'></td>";
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Add'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string SelectContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_id;
	if( !GetVariable( parameter, "contest_id", contest_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_id'." );
	unsigned long show_bots;
	if( !GetVariable( parameter, "show_bots", show_bots ) )
		show_bots = 0;
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<div width='100%' style='text-align: right;'><a href='/select_contestant.html?contest_id=%lu&start=%d&finish=%d&show_bots=%d'>%s bots</a></div>", contest_id, start, finish, show_bots ? 0 : 1, show_bots ? "hide" : "show" );
	result += "<form action='/add_contest_contestant.html' method='get' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_id' value='%lu'>", contest_id );
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Title</th>";
	result += "<th class='list' width='50px'>&nbsp;</th>";
	result += "<th class='list' width='25px'>&nbsp;</th>";
	result += "</tr>";
	{
		cLocker locker( *ContestantDataBase );
		int number = 1;
		for( nsContestantDataBase::NameIterator contestant_iterator = ContestantDataBase->BeginByName(); contestant_iterator != ContestantDataBase->EndByName(); ++contestant_iterator )
		{
			if( !show_bots && contestant_iterator->Status & nsContestantDataBase::STATUS_BOT )
				continue;
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contestant.html?contestant_id=%lu'>%s</a></td>", contestant_iterator->Key, contestant_iterator->Name );
				result += StringPrintf( "<td class='record' align='center'><a class='command' href='/add_contest_contestant.html?contest_id=%lu&contestant_id=%lu'>select</a></td>", contest_id, contestant_iterator->Key );
				result += StringPrintf( "<td class='record' align='center'><input type='checkbox' name='contestant_id' value='%lu'></td>", contestant_iterator->Key );
				result += "</tr>";
			}
			++count;
			++number;
		}
	}
	result += "</table>";
	result += "<div align='right'><input class='text' type='submit' value='Select'></div>";
	result += "</form>";
	result += TableControlBar( start, finish, count, parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string EditContestContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	vector< unsigned long > contest_contestant_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	// Чтение из базы
	//sContestContestantData contest_contestant_data;
	//if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) ) 
	//	return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	//sContestantData contestant_data;
	//if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
	//	return ErrorHtml( client_data, "Contestant doesn't exist." );
	bool first_contestant = true;
	bool is_year_same = true, is_month_same = true, is_day_same = true, is_hour_same = true, is_minute_same = true, is_second_same = true;
	unsigned short year, month, day, hour, minute, second;
	bool is_visibility_level_same = true;
	long visibility_level;
	bool is_addition_time_same = true;
	unsigned long addition_time;
	unsigned long contest_id;
	for( int i = 0; i < ( int )contest_contestant_id.size(); ++i )
	{
		sContestContestantData contest_contestant_data;
		if( ContestContestantDataBase->GetByKey( contest_contestant_id[ i ], contest_contestant_data ) ) 
		{
			if( first_contestant )
			{
				first_contestant = false;
				SplitTime( contest_contestant_data.StartTime, &year, &month, &day, NULL, &hour, &minute, &second, NULL );
				visibility_level = contest_contestant_data.VisibilityLevel;
				addition_time = contest_contestant_data.AdditionTime;
				contest_id = contest_contestant_data.ContestId;
			}
			else
			{
				unsigned short new_year, new_month, new_day, new_hour, new_minute, new_second;
				SplitTime( contest_contestant_data.StartTime, &new_year, &new_month, &new_day, NULL, &new_hour, &new_minute, &new_second, NULL );
				if( is_year_same && year != new_year )
					is_year_same = is_month_same = is_day_same = is_hour_same = is_minute_same = is_second_same = false;
				if( is_month_same && month != new_month )
					is_month_same = is_day_same = is_hour_same = is_minute_same = is_second_same = false;
				if( is_day_same && day != new_day )
					is_day_same = is_hour_same = is_minute_same = is_second_same = false;
				if( is_hour_same && hour != new_hour )
					is_hour_same = is_minute_same = is_second_same = false;
				if( is_minute_same && minute != new_minute )
					is_minute_same = is_second_same = false;
				if( is_second_same && second != new_second )
					is_second_same = false;
				if( is_visibility_level_same && visibility_level != contest_contestant_data.VisibilityLevel )
					is_visibility_level_same = false;
				if( is_addition_time_same && addition_time != contest_contestant_data.AdditionTime )
					is_addition_time_same = false;
				if( contest_id != contest_contestant_data.ContestId )
					return ErrorHtml( client_data, "Contest must be the same for selected contestants." );
			}
		}
	}
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_id, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	for( int i = 0; i < ( int )contest_contestant_id.size(); ++i )
	{
		sContestContestantData contest_contestant_data;
		if( ContestContestantDataBase->GetByKey( contest_contestant_id[ i ], contest_contestant_data ) ) 
		{
			sContestantData contestant_data;
			if( ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
				result += StringPrintf( "<a class='record' href='contestant.html?contestant_id=%lu'>%s</a><br>", contest_contestant_data.ContestantId, Escape( contestant_data.Name ).c_str() );
			else
				result += StringPrintf( "<a class='record' href='contestant.html?contestant_id=%lu'><font class='error'>Error</font></a><br>", contest_contestant_data.ContestantId );
		}
		else
			result += StringPrintf( "<a class='record' href='contest_contestant.html?contest_contestant_id=%lu'><font class='error'>Error</font></a><br>", contest_contestant_id[ i ] );
	}
//	result += StringPrintf( "<a class='record' href='contestant.html?contestant_id=%lu'>%s</a>", contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	result += "<hr>";
	result += "<form action='/edit_contest_contestant.action' method='post' enctype='application/x-www-form-urlencoded'>";
	for( int i = 0; i < ( int )contest_contestant_id.size(); ++i )
	{
		result += StringPrintf( "<input type='hidden' name='contest_contestant_id' value='%lu'>", contest_contestant_id[ i ] );
	}
	result += "<table class='edit' cellspacing='0'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Start time:</td>";
	result += "<td class='edit_field_value'>";
	if( is_hour_same )
		result += StringPrintf( "<input type='text' class='text' name='start_time_hour' value='%hu' size='2' maxlength='2'>", hour );
	else
		result += "<input type='text' class='text' name='start_time_hour' value='' size='2' maxlength='2'>";
	result += "<b>:</b>";
	if( is_minute_same )
		result += StringPrintf( "<input class='text' type='text' name='start_time_minute' value='%02hu' size='2' maxlength='2'>", minute );
	else
		result += "<input class='text' type='text' name='start_time_minute' value='' size='2' maxlength='2'>";
	result += "<b>:</b>";
	if( is_second_same )
		result += StringPrintf( "<input class='text' type='text' name='start_time_second' value='%02hu' size='2' maxlength='2'>", second );
	else
		result += "<input class='text' type='text' name='start_time_second' value='' size='2' maxlength='2'>";
	result += "&nbsp;&nbsp;&nbsp;";
	if( is_day_same )
		result += StringPrintf( "<input type='text' class='text' name='start_time_day' value='%02hu' size='2' maxlength='2'>", day );
	else
		result += "<input type='text' class='text' name='start_time_day' value='' size='2' maxlength='2'>";
	result += "<b>.</b>";
	if( is_month_same )
		result += StringPrintf( "<input type='text' class='text' name='start_time_month' value='%02hu' size='2' maxlength='2'>", month );
	else
		result += "<input type='text' class='text' name='start_time_month' value='' size='2' maxlength='2'>";
	result += "<b>.</b>";
	if( is_year_same )
		result += StringPrintf( "<input class='text' type='text' name='start_time_year' value='%04hu' maxlength='4' size='4'>", year );
	else
		result += "<input class='text' type='text' name='start_time_year' value='' maxlength='4' size='4'>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Visibility level:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='visibility_level'>";
	result += StringPrintf( "<option %s></option>", is_visibility_level_same ? "" : "selected" );
	result += StringPrintf( "<option value='%ld' %s>Blind</option>", VISIBILITY_LEVEL_BLIND, is_visibility_level_same && visibility_level == -1 ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Onsite</option>", VISIBILITY_LEVEL_ONSITE, is_visibility_level_same && visibility_level == 0 ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Virtual</option>", VISIBILITY_LEVEL_VIRTUAL, is_visibility_level_same && visibility_level == 1 ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Admin</option>", VISIBILITY_LEVEL_ADMIN, is_visibility_level_same && visibility_level == 2 ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>God</option>", VISIBILITY_LEVEL_GOD, is_visibility_level_same && visibility_level == 3 ? "selected" : "" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Addition time:</td>";
	result += "<td class='edit_field_value'>";
	if( is_addition_time_same )
		result += StringPrintf( "<input type='text' class='text' name='addition_time_hour' value='%lu' size='4' maxlength='4'>", addition_time / 60 / 60 );
	else
		result += "<input type='text' class='text' name='addition_time_hour' value='' size='4' maxlength='4'>";
	result += "<b>:</b>";
	if( is_addition_time_same )
		result += StringPrintf( "<input type='text' class='text' name='addition_time_minute' value='%02lu' size='2' maxlength='2'>", addition_time / 60 % 60 );
	else
		result += "<input type='text' class='text' name='addition_time_minute' value='' size='2' maxlength='2'>";
	result += "<b>:</b>";
	if( is_addition_time_same )
		result += StringPrintf( "<input type='text' class='text' name='addition_time_second' value='%02lu' size='2' maxlength='2'>", addition_time % 60 );
	else
		result += "<input type='text' class='text' name='addition_time_second' value='' size='2' maxlength='2'>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input class='submit' type='submit' value='Edit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string DeleteContestContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	vector< unsigned long > contest_contestant_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	// Чтение из базы
	//sContestContestantData contest_contestant_data;
	//if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) ) 
	//	return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	//sContestantData contestant_data;
	//if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
	//	return ErrorHtml( client_data, "Contestant doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/delete_contest_contestant.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='delete'>";
	for( int i = 0; i < ( int )contest_contestant_id.size(); ++i )
	{
		result += StringPrintf( "<input type='hidden' name='contest_contestant_id' value='%lu'>", contest_contestant_id[ i ] );
	}
	result += "<p class='delete'>Are you sure to delete ";
	for( int i = 0; i < ( int )contest_contestant_id.size(); ++i )
	{
		sContestContestantData contest_contestant_data;
		if( !ContestContestantDataBase->GetByKey( contest_contestant_id[ i ], contest_contestant_data ) ) 
			return ErrorHtml( client_data, "ContestContestant doesn't exist." );
		sContestantData contestant_data;
		if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
			return ErrorHtml( client_data, "Contestant doesn't exist." );
		if( i != 0 )
			result += ", ";
		result += StringPrintf( "<a class='delete' href='/contestant.html?contestant_id=%lu'>%s</a>", contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	}
	result += " from contest?</p>";
	result += "<input class='submit' type='submit' value='Confirm'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestContestantHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	// Чтение из базы
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) ) 
		return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<h1 class='title'>%s</h1>", Escape( contestant_data.Name ).c_str() );
	result += "<hr>";
	if( *contestant_data.Comment != '\0' )
	{
		result += StringPrintf( "<h2 class='comment'>%s</h2>", Escape( contestant_data.Comment ).c_str() );
		result += "<hr>";
	}
	result += StringPrintf( "<a class='record' href='/contest_contestant_problems.html?contest_contestant_id=%lu'>Submits</a><br>", contest_contestant_id );
	result += StringPrintf( "<a class='record' href='/monitor.html?contest_contestant_id=%lu'>Monitor</a>", contest_contestant_id );
	if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
	{
		result += "<hr>";
		result += StringPrintf( "<a class='record' href='/recalculate_real_times_of_submits.action?contest_contestant_id=%lu' onClick='return confirm( \"Are you shure?\" )'>Recalculate real times of submits</a><br>", contest_contestant_id );
		result += StringPrintf( "<a class='record' href='/recalculate_relative_times_of_submits.action?contest_contestant_id=%lu' onClick='return confirm( \"Are you shure?\" )'>Recalculate relative times of submits</a>", contest_contestant_id );
		result += "<hr>";
		result += StringPrintf( "<a class='record' href='/edit_contest_contestant.html?contest_contestant_id=%lu'>Edit</a><br>", contest_contestant_id );
		result += StringPrintf( "<a class='record' href='/delete_contest_contestant.html?contest_contestant_id=%lu'>Delete</a>", contest_contestant_id );
	}
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestContestantProblemsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) )
		return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING || contest_contestant_data.ContestantId == client_data.ContestantId ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	result += "<hr>";
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<th class='list'>#</th>";
	result += "<th class='list'>Time</th>";
	result += "<th class='list'>Problem</th>";
	result += "<th class='list'>Language</th>";
	result += "<th class='list'>Result</th>";
	result += "<th class='list'>Time</th>";
	result += "<th class='list'>Memory</th>";
	result += "<th class='list'>";
	if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
	{
		result += StringPrintf( "<a class='command' href='/add_contest_contestant_problem.html?contest_contestant_id=%lu'><img class='command' src='/plus.png' alt='add' title='Add new submission'></a>", contest_contestant_id );
	}
	result += "</th>";
	result += "</tr>";
	{
		cLocker problem_locker( *ProblemDataBase );
		cLocker language_locker( *LanguageDataBase );
		cLocker contest_problem_locker( *ContestProblemDataBase );
		cLocker contest_contestant_problem_locker( *ContestContestantProblemDataBase );
		nsContestContestantProblemDataBase::ContestContestantIdReverseIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->ReverseLowerBoundByContestContestantId( contest_contestant_id ), contest_contestant_problem_end = ContestContestantProblemDataBase->ReverseUpperBoundByContestContestantId( contest_contestant_id );
		int number = ( int )( contest_contestant_problem_end - contest_contestant_problem_iterator );
		for( ; contest_contestant_problem_iterator != contest_contestant_problem_end; ++contest_contestant_problem_iterator, --number )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%lu.</td>", number );
				result += StringPrintf( "<td class='record' align='center'>%lu:%02lu:%02lu</td>", contest_contestant_problem_iterator->RelativeTime / 60 / 60, contest_contestant_problem_iterator->RelativeTime / 60 % 60, contest_contestant_problem_iterator->RelativeTime % 60 );
				sContestProblemData contest_problem_data;
				sProblemData problem_data;
				if( ContestProblemDataBase->GetByKey( contest_contestant_problem_iterator->ContestProblemId, contest_problem_data ) )
					if( ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
//						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s. %s</a></td>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a></td>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
					else
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. <font class='error'>Error</font></a></td>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str() );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				sLanguageData language_data;
				if( contest_contestant_problem_iterator->LanguageId == BAD_KEY )
					result += StringPrintf( "<td class='record' align='center'>Undefined</td>" );
				else if( LanguageDataBase->GetByKey( contest_contestant_problem_iterator->LanguageId, language_data ) )
					result += StringPrintf( "<td class='record' align='center'>%s</td>", language_data.Title );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				result += StringPrintf( "<td class='record' align='center'>%s</td>", GetResult( *contest_contestant_problem_iterator ).c_str() );
				result += StringPrintf( "<td class='record' align='center'>%.3lf</td>", ( double )contest_contestant_problem_iterator->RunTime / 1000 );
				if( contest_contestant_problem_iterator->Memory < 1024000 )
					result += StringPrintf( "<td class='record' align='center'>%lu&nbsp;kB</td>", contest_contestant_problem_iterator->Memory / 1024 );
				else
					result += StringPrintf( "<td class='record' align='center'>%.2lf&nbsp;MB</td>", ( double )contest_contestant_problem_iterator->Memory / 1048576 );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='command' href='/contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/info.png' alt='info' title='View info'></a>", contest_contestant_problem_iterator->Key );
				if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
				{
					result += StringPrintf( "<a class='command' href='/rejudge.action?contest_contestant_problem_id=%lu'><img class='command' src='/refresh.png' alt='rejudge' title='Rejudge submission'></a>", contest_contestant_problem_iterator->Key );
					result += StringPrintf( "<a class='command' href='/edit_contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/pencil.png' alt='edit' title='Edit submission'></a>", contest_contestant_problem_iterator->Key );
					result += StringPrintf( "<a class='command' href='/delete_contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete submission'></a>", contest_contestant_problem_iterator->Key );
				}
				result += "</td>";
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += RefreshBar( parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string AddContestContestantProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_id;
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		contest_problem_id = BAD_KEY;
	// Чтение из базы
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) )
		return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	result += "<hr>";
	result += "<form action='/add_contest_contestant_problem.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_contestant_id' value='%lu'>", contest_contestant_id );
	result += "<table class='edit' cellspacing='0'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Problem:</td>";
	result += "<td class='edit_field_value'>";
	unsigned long plugin_id;
	if( contest_problem_id != BAD_KEY )
	{
		sContestProblemData contest_problem_data;
		if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
			return ErrorHtml( client_data, "ContestProblem doesn't exist." );
		sProblemData problem_data;
		if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
			return ErrorHtml( client_data, "Problem doesn't exist." );
		plugin_id = problem_data.PluginId;
		result += StringPrintf( "<input type='hidden' name='contest_problem_id' value='%lu'>", contest_problem_id );
//		result += StringPrintf( "<a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_id, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
		result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_id, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	}
	result += StringPrintf( "<a class='command' href='/select_contest_problem.html?contest_contestant_id=%lu'>select/change</a>", contest_contestant_id );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Time:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='relative_time_hour' value='%lu' size='4' maxlength='4'>", 0ul );
	result += "<b>:</b>";
	result += StringPrintf( "<input class='text' type='text' name='relative_time_minute' value='%02lu' size='2' maxlength='2'>", 0ul );
	result += "<b>:</b>";
	result += StringPrintf( "<input type='text' class='text' name='relative_time_second' value='%02lu' size='2' maxlength='2'>", 0ul );
	result += "</td>";
	result += "</tr>";
	unsigned short year, month, day, hour, minute, second, millisecond;
	SplitTime( client_data.Time, &year, &month, &day, NULL, &hour, &minute, &second, &millisecond );
	result += "<tr>";
	result += "<td class='edit_field_name'>Real time:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_day' value='%hu' size='2' maxlength='2'>", day );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_month' value='%hu' size='2' maxlength='2'>", month );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_year' value='%hu' size='4' maxlength='4'>", year );
	result += "<b>&nbsp;</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_hour' value='%hu' size='2' maxlength='2'>", hour );
	result += "<b>:</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_minute' value='%hu' size='2' maxlength='2'>", minute );
	result += "<b>:</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_second' value='%hu' size='2' maxlength='2'>", second );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_millisecond' value='%hu' size='3' maxlength='3'>", millisecond );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Result:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='result'>";
//	result += "<option></option>";
	result += StringPrintf( "<option value='%ld'>Accepted</option>", RESULT_ACCEPTED );
	result += StringPrintf( "<option value='%ld'>Wrong Answer</option>", RESULT_WRONG_ANSWER );
	result += StringPrintf( "<option value='%ld'>Time Limit Exceeded</option>", RESULT_TIME_LIMIT_EXCEEDED );
	result += StringPrintf( "<option value='%ld'>Run Time Error</option>", RESULT_RUN_TIME_ERROR );
	result += StringPrintf( "<option value='%ld'>Memory Limit Exceeded</option>", RESULT_MEMORY_LIMIT_EXCEEDED );
	result += StringPrintf( "<option value='%ld'>Output Limit Exceeded</option>", RESULT_OUTPUT_LIMIT_EXCEEDED );
	result += StringPrintf( "<option value='%ld'>Compilation Error</option>", RESULT_COMPILATION_ERROR );
	result += StringPrintf( "<option value='%ld'>Presentation Error</option>", RESULT_PRESENTATION_ERROR );
	result += StringPrintf( "<option value='%ld'>Security Violation</option>", RESULT_SECURITY_VIOLATION );
	result += StringPrintf( "<option value='%ld'>Source Limit Exceeded</option>", RESULT_SOURCE_LIMIT_EXCEEDED );
	result += StringPrintf( "<option value='%ld'>Submission Error</option>", RESULT_SUBMISSION_ERROR );
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Test number:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input type='text' class='text' name='test_number' value='0'>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Language:</td>";
	result += "<td class='edit_field_value'>";
	if( contest_problem_id != BAD_KEY )
	{
		//if( RefreshLanguages( plugin_id ) )
		//	return ErrorHtml( client_data, "AddContestContestantProblemHtml::RefreshLanguages returned false." );
		RefreshLanguages( plugin_id );
		cLocker locker( *LanguageDataBase );
		result += "<select name='language_id'>";
		for( nsLanguageDataBase::PluginIdIterator language_iterator = LanguageDataBase->LowerBoundByPluginId( plugin_id ), language_end = LanguageDataBase->UpperBoundByPluginId( plugin_id ); language_iterator != language_end; ++language_iterator )
		{
			result += StringPrintf( "<option value='%lu'>%s</option>", language_iterator->Key, language_iterator->Title );
		}
		result += "</select>";
	}
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Ip:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='ip0' value='%lu' size='3' maxlength='3'>", client_data.Ip >> 24 & 0xff );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='ip1' value='%lu' size='3' maxlength='3'>", client_data.Ip >> 16 & 0xff );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='ip2' value='%lu' size='3' maxlength='3'>", client_data.Ip >>  8 & 0xff );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='ip3' value='%lu' size='3' maxlength='3'>", client_data.Ip >>  0 & 0xff );
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Flags:</td>";
	result += "<td class='edit_field_value'>";
	result += "<input type='checkbox' name='no_rejudge' checked>Don't rejudge";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input type='hidden' name='code' value=''>";
	result += "<input type='hidden' name='run_time' value='0'>";
	result += "<input type='hidden' name='memory' value='0'>";
	result += "<input class='submit' type='submit' value='Add'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string SelectContestProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	// Чтение из базы
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) )
		return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) ) 
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
	result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	result += "<hr>";
	result += "<table cellspacing='0' width='100%' align='center'>";
	result += "<tr>";
	result += "<th class='list' width='25px'>#</th>";
	result += "<th class='list'>Title</th>";
	result += "<th class='list' width='50px'>&nbsp;</th>";
	result += "</tr>";
	{
		cLocker problem_locker( *ProblemDataBase );
		cLocker contest_problem_locker( *ContestProblemDataBase );
		for( nsContestProblemDataBase::ContestIdIterator contest_problem_iterator = ContestProblemDataBase->LowerBoundByContestId( contest_contestant_data.ContestId ), contest_problem_end = ContestProblemDataBase->UpperBoundByContestId( contest_contestant_data.ContestId ); contest_problem_iterator != contest_problem_end; ++contest_problem_iterator )
		{
			sProblemData problem_data;
			if( !ProblemDataBase->GetByKey( contest_problem_iterator->ProblemId, problem_data ) )
				return false;
			result += "<tr>";
			result += StringPrintf( "<td class='record' align='right'>%s.</td>", contest_problem_iterator->Letter );
//			result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s</a></td>", contest_problem_iterator->Key, problem_data.Header );
			result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s</a></td>", contest_problem_iterator->Key, problem_data.Header );
			result += StringPrintf( "<td class='record' align='center'><a class='command' href='/add_contest_contestant_problem.html?contest_contestant_id=%lu&contest_problem_id=%lu'>select</a></td>", contest_contestant_id, contest_problem_iterator->Key );
			result += "</tr>";
		}
	}
	result += "</table>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

//std::string SelectLanguageHtml( const sClientData &client_data, const cFormat parameter )
//{
//	// Получение информации о клиенте
//	sContestantData client_contestant_data;
//	GetContestantDataById( client_data.ContestantId, client_contestant_data );
//	// Проверка прав доступа к странице
//	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
//		return ErrorHtml( client_data, "You have no permission for this page." );
//	// Извлечение параметров
//	unsigned long contest_contestant_id;
//	unsigned long contest_problem_id;
//	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
//		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
//	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
//		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
//	// Чтение из базы
//	sContestContestantData contest_contestant_data;
//	if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) )
//		return ErrorHtml( client_data, "ContestContestant doesn't exist." );
//	sContestantData contestant_data;
//	if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) ) 
//		return ErrorHtml( client_data, "Contestant doesn't exist." );
//	sContestProblemData contest_problem_data;
//	if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
//		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
//	sProblemData problem_data;
//	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
//		return ErrorHtml( client_data, "Problem doesn't exist." );
//	sContestData contest_data;
//	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
//		return ErrorHtml( client_data, "Contest doesn't exist." );
//	// Генерация страницы
//	string center;
//	center += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
//	center += "<hr>";
//	center += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
//	center += "<hr>";
//	center += "<table cellspacing='0' width='100%' align='center'>";
//	center += "<tr>";
//	center += "<th class='list' width='25px'>#</th>";
//	center += "<th class='list'>Title</th>";
//	center += "<th class='list' width='50px'>Commands</th>";
//	center += "</tr>";
//	{
////		if( !RefreshLanguages( problem_data.PluginId ) )
////			return ErrorHtml( client_data, "SelectLanguageHtml::RefreshLanguages returned false." );
//		RefreshLanguages( problem_data.PluginId );
//		cLocker locker( *LanguageDataBase );
//		int number = 1;
//		for( nsLanguageDataBase::PluginIdIterator language_iterator = LanguageDataBase->LowerBoundByPluginId( problem_data.PluginId ), language_end = LanguageDataBase->UpperBoundByPluginId( problem_data.PluginId ); language_iterator != language_end; ++language_iterator, ++number )
//		{
//			center += "<tr>";
//			center += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
//			center += StringPrintf( "<td class='record' align='center'><a class='record' href='/language.html?language_id=%lu'>%s</a></td>", language_iterator->Key, language_iterator->Title );
//			center += StringPrintf( "<td class='record' align='center'><a class='command' href='/add_contest_contestant_problem.html?contest_contestant_id=%lu&contest_problem_id=%lu&language_id=%lu'>select</a></td>", contest_contestant_id, contest_problem_id, language_iterator->Key );
//			center += "</tr>";
//		}
//	}
//	center += "</table>";
//	return MainHtml( client_contestant_data, Triple( "", center, "" ) );
//}

std::string EditContestContestantProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_problem_id;
	if( !GetVariable( parameter, "contest_contestant_problem_id", contest_contestant_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_problem_id'." );
	// Чтение из базы
	sContestContestantProblemData contest_contestant_problem_data;
	if( !ContestContestantProblemDataBase->GetByKey( contest_contestant_problem_id, contest_contestant_problem_data ) )
		return ErrorHtml( client_data, "ContestContestantProblem doesn't exist." );
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByKey( contest_contestant_problem_data.ContestContestantId, contest_contestant_data ) )
		return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	sContestantData contestant_data;
	if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
		return ErrorHtml( client_data, "Contestant doesn't exist." );
	sContestProblemData contest_problem_data;
	if( !ContestProblemDataBase->GetByKey( contest_contestant_problem_data.ContestProblemId, contest_problem_data ) )
		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	//sLanguageData language_data;
	//if( !LanguageDataBase->GetByKey( contest_contestant_problem_data.LanguageId, language_data ) )
	//	return ErrorHtml( client_data, "Language doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";

	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";

	result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	result += "<hr>";

	//sContestContestantData contest_contestant_data;
	//if( ContestContestantDataBase->GetByKey( contest_contestant_problem_data.ContestContestantId, contest_contestant_data ) )
	//{
	//	sContestData contest_data;
	//	if( ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
	//		result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_contestant_data.ContestId, Escape( contest_data.Title ).c_str() );
	//	else
	//		result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><font class='error'><h1 class='title'>Error</h1></font></a>", contest_contestant_data.ContestId );
	//	result += "<hr>";
	//	sContestantData contestant_data;
	//	if( ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
	//		result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	//	else
	//		result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'><font class='error'>Error</font></a>", contest_contestant_data.Key );
	//}
	//else
	//{
	//	result += StringPrintf( "<font class='error'><h1 class='title'>Error</h1></font>" );
	//	result += "<hr>";
	//	result += StringPrintf( "<font class='error'>Error</font>" );
	//}
	//result += "<hr>";

	result += "<form action='/edit_contest_contestant_problem.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += StringPrintf( "<input type='hidden' name='contest_contestant_problem_id' value='%lu'>", contest_contestant_problem_id );
	result += "<table class='edit' cellspacing='0'>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Problem:</td>";
	result += "<td class='edit_field_value'>";
//	result += StringPrintf( "<a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	//sContestProblemData contest_problem_data;
	//if( ContestProblemDataBase->GetByKey( contest_contestant_problem_data.ContestProblemId, contest_problem_data ) )
	//{
	//	sProblemData problem_data;
	//	if( ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
	//		result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.ProblemId, contest_problem_data.Letter, problem_data.Header );
	//	else
	//		result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. <font class='error'>Error</font></a>", contest_contestant_problem_data.ContestProblemId, contest_problem_data.Letter );
	//}
	//else
	//	result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'><font class='error'>Error</font></a>", contest_contestant_problem_data.ContestProblemId );
	result += "</td>";
	result += "</tr>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Relative time:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='relative_time_hour' value='%lu' size='4' maxlength='4'>", contest_contestant_problem_data.RelativeTime / 60 / 60 );
	result += "<b>:</b>";
	result += StringPrintf( "<input class='text' type='text' name='relative_time_minute' value='%02lu' size='2' maxlength='2'>", contest_contestant_problem_data.RelativeTime / 60 % 60 );
	result += "<b>:</b>";
	result += StringPrintf( "<input type='text' class='text' name='relative_time_second' value='%02lu' size='2' maxlength='2'>", contest_contestant_problem_data.RelativeTime % 60 );
	result += "</td>";
	result += "</tr>";

	unsigned short year, month, day, hour, minute, second, millisecond;
	SplitTime( contest_contestant_problem_data.RealTime, &year, &month, &day, NULL, &hour, &minute, &second, &millisecond );
	result += "<tr>";
	result += "<td class='edit_field_name'>Real time:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_day' value='%hu' size='2' maxlength='2'>", day );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_month' value='%hu' size='2' maxlength='2'>", month );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_year' value='%hu' size='4' maxlength='4'>", year );
	result += "<b>&nbsp;</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_hour' value='%hu' size='2' maxlength='2'>", hour );
	result += "<b>:</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_minute' value='%hu' size='2' maxlength='2'>", minute );
	result += "<b>:</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_second' value='%hu' size='2' maxlength='2'>", second );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='real_time_millisecond' value='%hu' size='3' maxlength='3'>", millisecond );
	result += "</td>";
	result += "</tr>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Result:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='result'>";
//	result += "<option></option>";
	result += StringPrintf( "<option value='%ld' %s>Accepted</option>", RESULT_ACCEPTED, contest_contestant_problem_data.Result == RESULT_ACCEPTED ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Wrong Answer</option>", RESULT_WRONG_ANSWER, contest_contestant_problem_data.Result == RESULT_WRONG_ANSWER ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Time Limit Exceeded</option>", RESULT_TIME_LIMIT_EXCEEDED, contest_contestant_problem_data.Result == RESULT_TIME_LIMIT_EXCEEDED ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Run Time Error</option>", RESULT_RUN_TIME_ERROR, contest_contestant_problem_data.Result == RESULT_RUN_TIME_ERROR ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Memory Limit Exceeded</option>", RESULT_MEMORY_LIMIT_EXCEEDED, contest_contestant_problem_data.Result == RESULT_MEMORY_LIMIT_EXCEEDED ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Output Limit Exceeded</option>", RESULT_OUTPUT_LIMIT_EXCEEDED, contest_contestant_problem_data.Result == RESULT_OUTPUT_LIMIT_EXCEEDED ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Compilation Error</option>", RESULT_COMPILATION_ERROR, contest_contestant_problem_data.Result == RESULT_COMPILATION_ERROR ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Presentation Error</option>", RESULT_PRESENTATION_ERROR, contest_contestant_problem_data.Result == RESULT_PRESENTATION_ERROR ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Security Violation</option>", RESULT_SECURITY_VIOLATION, contest_contestant_problem_data.Result == RESULT_SECURITY_VIOLATION ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Source Limit Exceeded</option>", RESULT_SOURCE_LIMIT_EXCEEDED, contest_contestant_problem_data.Result == RESULT_SOURCE_LIMIT_EXCEEDED ? "selected" : "" );
	result += StringPrintf( "<option value='%ld' %s>Submission Error</option>", RESULT_SUBMISSION_ERROR, contest_contestant_problem_data.Result == RESULT_SUBMISSION_ERROR ? "selected" : "" );
	result += "</select>";
	result += "</td>";
	result += "</tr>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Test number:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input type='text' class='text' name='test_number' value='%hu'>", contest_contestant_problem_data.TestNumber );
	result += "</td>";
	result += "</tr>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Language:</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='language_id'>";
	{
		//if( !RefreshLanguages( language_data.PluginId ) )
		//	return ErrorHtml( client_data, "EditContestContestantProblemHtml::RefreshLanguages returned false." );
		RefreshLanguages( problem_data.PluginId );
		cLocker locker( *LanguageDataBase );
		for( nsLanguageDataBase::PluginIdIterator language_iterator = LanguageDataBase->LowerBoundByPluginId( problem_data.PluginId ), language_end = LanguageDataBase->UpperBoundByPluginId( problem_data.PluginId ); language_iterator != language_end; ++language_iterator )
		{
			result += StringPrintf( "<option value='%lu' %s>%s</option>", language_iterator->Key, language_iterator->Key == contest_contestant_problem_data.LanguageId ? "selected" : "", language_iterator->Title );
		}
	}
	result += "</select>";
	result += "</td>";
	result += "</tr>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Ip:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input class='text' type='text' name='ip0' value='%lu' size='3' maxlength='3'>", contest_contestant_problem_data.Ip >> 24 & 0xff );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='ip1' value='%lu' size='3' maxlength='3'>", contest_contestant_problem_data.Ip >> 16 & 0xff );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='ip2' value='%lu' size='3' maxlength='3'>", contest_contestant_problem_data.Ip >>  8 & 0xff );
	result += "<b>.</b>";
	result += StringPrintf( "<input class='text' type='text' name='ip3' value='%lu' size='3' maxlength='3'>", contest_contestant_problem_data.Ip >>  0 & 0xff );
	result += "</td>";
	result += "</tr>";

	result += "<tr>";
	result += "<td class='edit_field_name'>Flags:</td>";
	result += "<td class='edit_field_value'>";
	result += StringPrintf( "<input type='checkbox' name='no_rejudge' %s>Don't rejudge", contest_contestant_problem_data.Flags & nsContestContestantProblemDataBase::FLAG_NO_REJUDGE ? "checked" : "" );
	result += "</td>";
	result += "</tr>";

	result += "</table>";
	result += StringPrintf( "<input type='hidden' name='run_time' value='%lu'>", contest_contestant_problem_data.RunTime );
	result += StringPrintf( "<input type='hidden' name='memory' value='%lu'>", contest_contestant_problem_data.Memory );
	result += "<input class='submit' type='submit' value='Edit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string DeleteContestContestantProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_problem_id;
	if( !GetVariable( parameter, "contest_contestant_problem_id", contest_contestant_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_problem_id'." );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<form action='/delete_contest_contestant_problem.action' method='post' enctype='application/x-www-form-urlencoded'>";
	result += "<div class='delete'>";
	result += StringPrintf( "<input type='hidden' name='contest_contestant_problem_id' value='%lu'>", contest_contestant_problem_id );
	result += "<p class='delete'>Are you sure to delete the submit?</p>";
	result += "<input class='submit' type='submit' value='Confirm'>";
	result += "</div>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestProblemContestantsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	sContestProblemData contest_problem_data;
	if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_problem_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
//	result += StringPrintf( "<a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_id, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_id, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	result += "<hr>";
	result += "<table cellspacing='0' width='100%'>";
	result += "<tr>";
	result += "<th class='list'>#</th>";
	result += "<th class='list'>Time</th>";
	result += "<th class='list'>Contestant</th>";
	result += "<th class='list'>Language</th>";
	result += "<th class='list'>Result</th>";
	result += "<th class='list'>Time</th>";
	result += "<th class='list'>Memory</th>";
	result += "<th class='list'>&nbsp;</th>";
	result += "</tr>";
	{
		cLocker contestant_locker( *ContestantDataBase );
		cLocker language_locker( *LanguageDataBase );
		cLocker contest_contestant_locker( *ContestContestantDataBase );
		cLocker contest_contestant_problem_locker( *ContestContestantProblemDataBase );
		nsContestContestantProblemDataBase::ContestProblemIdReverseIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->ReverseLowerBoundByContestProblemId( contest_problem_id ), contest_contestant_problem_end = ContestContestantProblemDataBase->ReverseUpperBoundByContestProblemId( contest_problem_id );
		int number = contest_contestant_problem_end - contest_contestant_problem_iterator;
		for( ; contest_contestant_problem_iterator != contest_contestant_problem_end; ++contest_contestant_problem_iterator, --number )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				result += StringPrintf( "<td class='record' align='center'>%lu:%02lu:%02lu</td>", contest_contestant_problem_iterator->RelativeTime / 60 / 60, contest_contestant_problem_iterator->RelativeTime / 60 % 60, contest_contestant_problem_iterator->RelativeTime % 60 );
				sContestContestantData contest_contestant_data;
				sContestantData contestant_data;
				if( ContestContestantDataBase->GetByKey( contest_contestant_problem_iterator->ContestContestantId, contest_contestant_data ) )
					if( ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a></td>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
					else
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'><font class='error'>Error</font></a></td>", contest_contestant_data.Key );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				sLanguageData language_data;
				if( contest_contestant_problem_iterator->LanguageId == BAD_KEY )
					result += StringPrintf( "<td class='record' align='center'>Undefined</td>" );
				else if( LanguageDataBase->GetByKey( contest_contestant_problem_iterator->LanguageId, language_data ) )
					result += StringPrintf( "<td class='record' align='center'>%s</td>", language_data.Title );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				result += StringPrintf( "<td class='record' align='center'>%s</td>", GetResult( *contest_contestant_problem_iterator ).c_str() );
				result += StringPrintf( "<td class='record' align='center'>%.3lf</td>", ( double )contest_contestant_problem_iterator->RunTime / 1000 );
				if( contest_contestant_problem_iterator->Memory < 1024000 )
					result += StringPrintf( "<td class='record' align='center'>%lu&nbsp;kB</td>", contest_contestant_problem_iterator->Memory / 1024 );
				else
					result += StringPrintf( "<td class='record' align='center'>%.2lf&nbsp;MB</td>", ( double )contest_contestant_problem_iterator->Memory / 1048576 );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='command' href='/rejudge.action?contest_contestant_problem_id=%lu'><img class='command' src='/refresh.png' alt='rejudge' title='Rejudge submission'></a>", contest_contestant_problem_iterator->Key );
				result += StringPrintf( "<a class='command' href='/contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/info.png' alt='info' title='View info'></a>", contest_contestant_problem_iterator->Key );
				result += StringPrintf( "<a class='command' href='/edit_contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/pencil.png' alt='edit' title='Edit submission'></a>", contest_contestant_problem_iterator->Key );
				result += StringPrintf( "<a class='command' href='/delete_contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete submission'></a>", contest_contestant_problem_iterator->Key );
				result += "</td>";
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += RefreshBar( parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result ); 
}

struct sProblem
{
	unsigned long Id;
	string Letter;
	string Header;
	unsigned long AcceptedCount;
	unsigned long RejectedCount;
	sProblem( unsigned long id, const string &letter, const string &header )
		: Id( id )
		, Letter( letter )
		, Header( header )
		, AcceptedCount( 0 )
		, RejectedCount( 0 )
	{
	}
	sProblem( const sProblem &problem )
		: Id( problem.Id )
		, Letter( problem.Letter )
		, Header( problem.Header )
		, AcceptedCount( problem.AcceptedCount )
		, RejectedCount( problem.RejectedCount )
	{
	}
	sProblem &operator =( const sProblem &problem )
	{
		Id = problem.Id;
		Letter = problem.Letter;
		Header = problem.Header;
		AcceptedCount = problem.AcceptedCount;
		RejectedCount = problem.RejectedCount;
		return *this;
	}
};

struct sProblemState
{
	bool IsAccepted;
	int RejectedCount;
	int Time;
	sProblemState()
		: IsAccepted( false )
		, RejectedCount( 0 )
		, Time( 0 )
	{
	}
	sProblemState( const sProblemState &problem_state )
		: IsAccepted( problem_state.IsAccepted )
		, RejectedCount( problem_state.RejectedCount )
		, Time( problem_state.Time )
	{
	}
	sProblemState &operator =( const sProblemState &problem_state )
	{
		IsAccepted = problem_state.IsAccepted;
		RejectedCount = problem_state.RejectedCount;
		Time = problem_state.Time;
		return *this;
	}
};

struct sContestant
{
	unsigned long Id;
	int MinRank, MaxRank;
	string Name;
	int SolvedCount;
	int Time;
	int LastAcceptedTime;
	int Color;
	double Rating;
	sContestant( unsigned long id, const string &name )
		: Id( id )
		, MinRank( 0 )
		, MaxRank( 0 )
		, Name( name )
		, SolvedCount( 0 )
		, Time( 0 )
		, LastAcceptedTime( 0 )
		, Color( 0 )
		, Rating( 0 )
	{
	}
	sContestant( const sContestant &contestant )
		: Id( contestant.Id )
		, MinRank( contestant.MinRank )
		, MaxRank( contestant.MaxRank )
		, Name( contestant.Name )
		, SolvedCount( contestant.SolvedCount )
		, Time( contestant.Time )
		, LastAcceptedTime( contestant.LastAcceptedTime )
		, Color( contestant.Color )
		, Rating( contestant.Rating )
	{
	}
	sContestant &operator =( const sContestant &contestant )
	{
		Id = contestant.Id;
		MinRank = contestant.MinRank;
		MaxRank = contestant.MaxRank;
		Name = contestant.Name;
		SolvedCount = contestant.SolvedCount;
		Time = contestant.Time;
		LastAcceptedTime = contestant.LastAcceptedTime;
		Color = contestant.Color;
		Rating = contestant.Rating;
		return *this;
	}
};

static bool Compare( const sContestant *c1, const sContestant *c2 )
{
	if( c1->SolvedCount > c2->SolvedCount )
		return true;
	if( c1->SolvedCount < c2->SolvedCount )
		return false;
	if( c1->Time < c2->Time )
		return true;
	if( c1->Time > c2->Time )
		return false;
	if( c1->LastAcceptedTime < c2->LastAcceptedTime )
		return true;
	if( c1->LastAcceptedTime > c2->LastAcceptedTime )
		return false;
	return false;
}

std::string MonitorHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_id;
	if( !GetVariable( parameter, "contest_contestant_id", contest_contestant_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_contestant_id'." );
	unsigned long show_bots;
	if( !GetVariable( parameter, "show_bots", show_bots ) )
		show_bots = 1;
	// Чтение из базы
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByKey( contest_contestant_id, contest_contestant_data ) )
		return ErrorHtml( client_data, "Contest is not started." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_WATCHING || contest_contestant_data.ContestantId == client_data.ContestantId ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Генерация монитора
	int i, j;
	unsigned long long current_time = client_data.Time;
	long long elapsed_time = ( long long )( current_time - contest_contestant_data.StartTime );
	long long duration = ( long long )( contest_data.Duration + contest_contestant_data.AdditionTime ) * 10000000;
	long long remain_time = duration - elapsed_time;
	long long monitor_time = elapsed_time;
	long long frozen_time = ( long long )contest_data.FrozenTime * 10000000;
	bool is_frozen = contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED && frozen_time <= elapsed_time;
	if( monitor_time >= duration )
		monitor_time = duration;
	if( contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED )
	{
		if( monitor_time >= frozen_time )
			monitor_time = frozen_time;
	}
	vector< sProblem > problem;
	vector< sContestant > contestant;
	vector< vector< sProblemState > > state;
	vector< int > index;
	int max_solved_count = 0;
	{
		cLocker contestant_locker( *ContestantDataBase );
		cLocker problem_locker( *ProblemDataBase );
		cLocker contest_contestant_locker( *ContestContestantDataBase );
		cLocker contest_problem_locker( *ContestProblemDataBase );
		cLocker contest_contestant_problem_locker( *ContestContestantProblemDataBase );

		if( monitor_time >= 0 )
		{
			for( nsContestProblemDataBase::ContestIdIterator contest_problem_iterator = ContestProblemDataBase->LowerBoundByContestId( contest_contestant_data.ContestId ), contest_problem_end = ContestProblemDataBase->UpperBoundByContestId( contest_contestant_data.ContestId ); contest_problem_iterator != contest_problem_end; ++contest_problem_iterator )
			{
				sProblemData problem_data;
				if( !ProblemDataBase->GetByKey( contest_problem_iterator->ProblemId, problem_data ) )
					return false;
				problem.push_back( sProblem( contest_problem_iterator->Key, contest_problem_iterator->Letter, problem_data.Header ) );
			}
		}

		for( nsContestContestantDataBase::ContestIdIterator contest_contestant_iterator = ContestContestantDataBase->LowerBoundByContestId( contest_data.Key ), contest_contestant_end = ContestContestantDataBase->UpperBoundByContestId( contest_data.Key ); contest_contestant_iterator != contest_contestant_end; ++contest_contestant_iterator )
		{
			if( contest_contestant_iterator->VisibilityLevel > contest_contestant_data.VisibilityLevel )
				continue;
			sContestantData contestant_data;
			if( !ContestantDataBase->GetByKey( contest_contestant_iterator->ContestantId, contestant_data ) )
				return false;
			if( !show_bots && contestant_data.Status & nsContestantDataBase::STATUS_BOT )
				continue;
			contestant.push_back( sContestant( contest_contestant_iterator->Key, Escape( contestant_data.Name ) ) );
		}

		state.resize( contestant.size(), vector< sProblemState >( problem.size() ) );
		for( i = 0; i < ( int )contestant.size(); ++i )
		{
			for( j = 0; j < ( int )problem.size(); ++j )
			{
				for( nsContestContestantProblemDataBase::ContestContestantProblemIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->LowerBoundByContestContestantProblem( contestant[ i ].Id, problem[ j ].Id ), contest_contestant_problem_end = ContestContestantProblemDataBase->UpperBoundByContestContestantProblem( contestant[ i ].Id, problem[ j ].Id ); contest_contestant_problem_iterator != contest_contestant_problem_end; ++contest_contestant_problem_iterator )
				{
					if( monitor_time <= ( long long )contest_contestant_problem_iterator->RelativeTime * 10000000 )
						break;
					if( contest_contestant_problem_iterator->Result < 0 )
						continue;
					//if( state[ i ][ j ].IsAccepted )
					//	continue;
					else if( contest_contestant_problem_iterator->Result == RESULT_ACCEPTED )
					{
						state[ i ][ j ].IsAccepted = true;
						state[ i ][ j ].Time = contest_contestant_problem_iterator->RelativeTime / 60;
						++contestant[ i ].SolvedCount;
						contestant[ i ].Time += state[ i ][ j ].Time + state[ i ][ j ].RejectedCount * contest_data.Penalty;
						++problem[ j ].AcceptedCount;
						if( contestant[ i ].LastAcceptedTime < state[ i ][ j ].Time )
							contestant[ i ].LastAcceptedTime = state[ i ][ j ].Time;
						if( max_solved_count < contestant[ i ].SolvedCount )
							max_solved_count = contestant[ i ].SolvedCount;
						break;
					}
					else
					{
						++state[ i ][ j ].RejectedCount;
						++problem[ j ].RejectedCount;
					}
				}
			}
		}
		
		vector< sContestant * > pindex;
		for( i = 0; i < ( int )contestant.size(); ++i )
		{
			pindex.push_back( &contestant[ i ] );
		}

		sort( pindex.begin(), pindex.end(), Compare );

		for( i = 0; i < ( int )pindex.size(); ++i )
		{
			index.push_back( pindex[ i ] - &contestant[ 0 ] );
		}

		// Вычисляем место
		for( i = 0; i < ( int )contestant.size(); ++i )
		{
			if( i > 0 && !Compare( &contestant[ index[ i - 1 ] ], &contestant[ index[ i ] ] ) )
				contestant[ index[ i ] ].MinRank = contestant[ index[ i - 1 ] ].MinRank;
			else
				contestant[ index[ i ] ].MinRank = i + 1;
		}
		for( i = ( int )contestant.size() - 1; i >= 0; --i )
		{
			if( i < ( int )contestant.size() - 1 && !Compare( &contestant[ index[ i ] ], &contestant[ index[ i + 1 ] ] ) )
				contestant[ index[ i ] ].MaxRank = contestant[ index[ i + 1 ] ].MaxRank;
			else
				contestant[ index[ i ] ].MaxRank = i + 1;
		}

		// Вычисляем рейтинг
		for( i = 0; i < ( int )contestant.size(); ++i )
		{
			if( contestant[ i ].SolvedCount != 0 )
				contestant[ i ].Rating = 200. * contestant[ i ].SolvedCount / max_solved_count * ( ( int )contestant.size() - 1 ) / ( ( int )contestant.size() - 1 + contestant[ i ].MinRank - 1 );
			else
				contestant[ i ].Rating = 0;
		}

		// Вычисляем цвет
		if( contestant.size() > 0 )
		{
			contestant[ index.back() ].Color = 0;
			for( i = ( int )contestant.size() - 2; i >= 0; --i )
			{
				if( contestant[ index[ i ] ].SolvedCount == contestant[ index[ i + 1 ] ].SolvedCount )
					contestant[ index[ i ] ].Color = contestant[ index[ i + 1 ] ].Color ^ 1;
				else
					contestant[ index[ i ] ].Color = contestant[ index[ i + 1 ] ].Color ^ 3;
			}
			for( i = 0; i < ( int )contestant.size(); ++i )
			{
				if( contestant[ index[ i ] ].Id == contest_contestant_id )
					contestant[ index[ i ] ].Color = 4;
			}
		}
	}
	// Генерация страницы
	string result;
	result += "<html>";
	result += "<head>";
	result += "<title>ACM Server</title>";
	result += "<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>";
	long refresh;
	if( GetVariable( parameter, "refresh", refresh ) && refresh != 0 )
		result += StringPrintf( "<meta http-equiv='refresh' content='%ld'>", refresh );
	result += "<style type='text/css'>\r\n";
	result += "a { font-family: times new roman; font-size: 16px; }\r\n";
	result += "a:link { text-decoration: none; }\r\n";
	result += "a:visited { text-decoration: none; }\r\n";
	result += "a:hover { text-decoration: underline; }\r\n";
	result += "a:active { text-decoration: underline; }\r\n";
	result += "b { font-family: courier; font-size: 16px; font-weight: normal; }\r\n";
	result += "i { font-family: courier; font-size: 16px; font-style: normal; }\r\n";
	result += "s { font-family: courier; font-size: 16px; text-decoration: none; }\r\n";
	result += "u { font-family: arial; font-size: 13px; text-decoration: none; }\r\n";
	result += "td { padding: 5px; text-align: center; }\r\n";
	result += "div.refresh_control       { text-align: right; padding: 10px; }\r\n";
	result += "a.refresh_control         { font-family: arial; font-size: 12px; font-weight: normal; }\r\n";
	result += "a.refresh_control:link    { text-decoration: none; color: mediumblue; }\r\n";
	result += "a.refresh_control:visited { text-decoration: none; color: mediumblue; }\r\n";
	result += "a.refresh_control:hover   { text-decoration: underline; color: crimson; }\r\n";
	result += "a.refresh_control:active  { text-decoration: underline; color: crimson; }\r\n";
	result += "font.refresh_control      { font-family: arial; font-size: 12px; font-weight: normal; color: black; }\r\n";
	result += "</style>";
	result += "</head>";
	result += "<body style='text-align: center;'>";
	result += StringPrintf( "<a style='font-family: comic sans ms, arial; font-size: 24px; font-weight: bold; ' href='/contest.html?contest_id=%lu'>%s</a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<font style='font-family: tahoma, arial; font-size: 14px;'>";
	result += StringPrintf( "<br>Duration:&nbsp;%I64u:%02I64u", duration / 10000000 / 60 / 60, duration / 10000000 / 60 % 60 );
	if( elapsed_time < 0 )
	{
		result += StringPrintf( "<br>Starts in:&nbsp;%I64u:%02I64u:%02I64u", -elapsed_time / 10000000 / 60 / 60, -elapsed_time / 10000000 / 60 % 60, -elapsed_time / 10000000 % 60 );
		result += "<br>State:&nbsp;Not started";
	}
	else if( remain_time < 0 )
	{
		if( contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED )
			result += "<br>State:&nbsp;Finished, Frozen";
		else
			result += "<br>State:&nbsp;Finished";
	}
	else
	{
		result += StringPrintf( "<br>Time elapsed:&nbsp;%I64u:%02I64u:%02I64u", elapsed_time / 10000000 / 60 / 60, elapsed_time / 10000000 / 60 % 60, elapsed_time / 10000000 % 60 );
		result += StringPrintf( "<br>Time remain:&nbsp;%I64u:%02I64u:%02I64u", remain_time / 10000000 / 60 / 60, remain_time / 10000000 / 60 % 60, remain_time / 10000000 % 60 );
		if( contest_data.Flags & nsContestDataBase::FLAG_FROZEN_ENABLED && frozen_time <= elapsed_time )
			result += "<br>State:&nbsp;Frozen";
		else
			result += "<br>State:&nbsp;In progress";
	}
	result += "</font>";
	result += RefreshBar( parameter );
	( cFormat() = parameter )[ "show_bots" ] = StringPrintf( "%lu", ( unsigned long )!show_bots );
	result += StringPrintf( "<div width='100%' style='text-align: right;'><a href='/monitor.html?%s'>%s bots</a></div>", MakeParameters( parameter ).c_str(), show_bots ? "hide" : "show" );	
	result += "<table align='center' cellspacing='1'>";
	result += "<tr>";
	result += "<th>Rank</th>";
	result += "<th>Name</th>";
	for( i = 0; i < ( int )problem.size(); ++i )
	{
//		result += StringPrintf( "<th><a href='/contest_problem_frame.html?contest_problem_id=%lu'>%s</a></th>", problem[ i ].Id, problem[ i ].Letter.c_str() );
		result += StringPrintf( "<th><a href='/contest_problem.html?contest_problem_id=%lu' title='%s'>%s</a></th>", problem[ i ].Id, Escape( problem[ i ].Header ).c_str(), problem[ i ].Letter.c_str() );
	}
	result += "<th>Total</th>";
	result += "<th>Time</th>";
	if( contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING )
		result += "<th>Rating</th>";
	result += "</tr>";
	for( i = 0; i < ( int )contestant.size(); ++i )
	{
		static char *color[ 2 ][ 5 ] = 
		{
			{ "whitesmoke", "#E4E4E4", "#99FFBB", "#88EEAA", "pink" },
			{ "#EEEEFF", "#DDDDEE", "#77DDFF", "#66CCEE", "pink" }
		};
		result += StringPrintf( "<tr bgcolor='%s'>", color[ is_frozen ][ contestant[ index[ i ] ].Color ] );
		if( contestant[ index[ i ] ].MinRank == contestant[ index[ i ] ].MaxRank )
			result += StringPrintf( "<td><i>%d</i></td>", contestant[ index[ i ] ].MinRank );
		else
			result += StringPrintf( "<td><i>%d-%d</i></td>", contestant[ index[ i ] ].MinRank, contestant[ index[ i ] ].MaxRank );
		result += StringPrintf( "<td><a href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a></td>", contestant[ index[ i ] ].Id, contestant[ index[ i ] ].Name.c_str() );
		for( j = 0; j < ( int )problem.size(); ++j )
		{
			result += "<td>";
			result += "<s>";
			if( state[ index[ i ] ][ j ].IsAccepted )
				result += "+";
			else
				result += "-";
			if( state[ index[ i ] ][ j ].RejectedCount != 0 )
				result += StringPrintf( "%d", state[ index[ i ] ][ j ].RejectedCount );
			result += "</s>";
			result += "<br>";
			if( state[ index[ i ] ][ j ].IsAccepted )
				result += StringPrintf( "<u>%lu:%02lu</u>", state[ index[ i ] ][ j ].Time / 60, state[ index[ i ] ][ j ].Time % 60 );
			result += "</td>";
		}
		result += StringPrintf( "<td><i>%d</i></td>", contestant[ index[ i ] ].SolvedCount );
		result += StringPrintf( "<td><i>%d</i></td>", contestant[ index[ i ] ].Time );
		if( contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING )
			result += StringPrintf( "<td><i>%.2lf</i></td>", contestant[ index[ i ] ].Rating );
		result += "</tr>";
	}
	result += "<tr>";
	result += "<td></td>";
	result += "<td><b>Submissions</b></td>";
	for( i = 0; i < ( int )problem.size(); ++i )
	{
		result += StringPrintf( "<td><b>%d</b></td>", problem[ i ].AcceptedCount + problem[ i ].RejectedCount );
	}
	result += "<td></td>";
	result += "<td></td>";
	if( contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING )
		result += "<td></td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td></td>";
	result += "<td><b>Accepted</b></td>";
	for( i = 0; i < ( int )problem.size(); ++i )
	{
		result += StringPrintf( "<td><b>%d</b></td>", problem[ i ].AcceptedCount );
	}
	result += "<td></td>";
	result += "<td></td>";
	if( contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING )
		result += "<td></td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td></td>";
	result += "<td><b>Solvability</b></td>";
	for( i = 0; i < ( int )problem.size(); ++i )
	{
		int solvability = 0;
		if( problem[ i ].AcceptedCount + problem[ i ].RejectedCount != 0 )
			solvability = problem[ i ].AcceptedCount * 100 / ( problem[ i ].AcceptedCount + problem[ i ].RejectedCount );
		result += StringPrintf( "<td><b>%d%%</b></td>", solvability );
	}
	result += "<td></td>";
	result += "<td></td>";
	if( contest_data.Flags & nsContestDataBase::FLAG_ITMO_RATING )
		result += "<td></td>";
	result += "</tr>";
	result += "</table>";
	result += "</body>";
	result += "</html>";
	return result;
}

std::string SubmitHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_problem_id;
	if( !GetVariable( parameter, "contest_problem_id", contest_problem_id ) )
		return ErrorHtml( client_data, "This page requires integer variable 'contest_problem_id'." );
	// Чтение из базы
	sContestProblemData contest_problem_data;
	if( !ContestProblemDataBase->GetByKey( contest_problem_id, contest_problem_data ) )
		return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	sContestData contest_data;
	if( !ContestDataBase->GetByKey( contest_problem_data.ContestId, contest_data ) )
		return ErrorHtml( client_data, "Contest doesn't exist." );
	sProblemData problem_data;
	if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
		return ErrorHtml( client_data, "Problem doesn't exist." );
	sContestContestantData contest_contestant_data;
	if( !ContestContestantDataBase->GetByContestContestant( contest_data.Key, client_data.ContestantId, contest_contestant_data ) )
		return ErrorHtml( client_data, "Contest is not started." );
	if( client_data.Time < contest_contestant_data.StartTime )
		return ErrorHtml( client_data, "Contest is not started." );
	// Генерация страницы
	string result;
	result += "<center>";
	result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_data.Key, Escape( contest_data.Title ).c_str() );
	result += "<hr>";
//	result += StringPrintf( "<a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	result += "<hr>";
	result += "<form action='/submit.action' method='post' enctype='multipart/form-data'>";
	result += StringPrintf( "<input type='hidden' name='contest_problem_id' value='%lu'>", contest_problem_id );
	result += "<table cellspacing='0' align='center' width='100%'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Language</td>";
	result += "<td class='edit_field_value'>";
	result += "<select name='language_id'>";
	{
		RefreshLanguages( problem_data.PluginId );
		cLocker locker( *LanguageDataBase );
		for( nsLanguageDataBase::PluginIdIterator language_iterator = LanguageDataBase->LowerBoundByPluginId( problem_data.PluginId ), language_end = LanguageDataBase->UpperBoundByPluginId( problem_data.PluginId ); language_iterator != language_end; ++language_iterator )
		{
			result += StringPrintf( "<option value='%lu'>%s</option>", language_iterator->Key, language_iterator->Title );
		}
	}
	result += "</select>";
	result += "</td>";
	result += "</tr>";
	result += "<tr>";
	result += "<td class='edit_field_name'>Source code</td>";
	result += "<td class='edit_field_value'>";
//	result += "<input class='text' type='file' name='code' size='50'>";
	result += "<textarea class='text' name='code' rows='10' cols='50'></textarea>";
	result += "</td>";
	result += "</tr>";
	result += "</table>";
	result += "<input type='submit' class='submit' value='Submit'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestContestantProblemHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTESTS_BROWSING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	unsigned long contest_contestant_problem_id;
	if( !GetVariable( parameter, "contest_contestant_problem_id", contest_contestant_problem_id ) )
		return ErrorHtml( client_data, "This page required interger variable 'contest_contestant_problem_id'." );
	// Чтение из базы
	sContestContestantProblemData contest_contestant_problem_data;
	if( !ContestContestantProblemDataBase->GetByKey( contest_contestant_problem_id, contest_contestant_problem_data ) )
		return ErrorHtml( client_data, "ContestContestantProblem doesn't exist." );
	//sContestContestantData contest_contestant_data;
	//if( !ContestContestantDataBase->GetByKey( contest_contestant_problem_data.ContestContestantId, contest_contestant_data ) )
	//	return ErrorHtml( client_data, "ContestContestant doesn't exist." );
	//sContestantData contestant_data;
	//if( !ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
	//	ErrorHtml( client_data, "Contestant doesn't exist." );
	//sContestData contest_data;
	//if( !ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
	//	return ErrorHtml( client_data, "Contest doesn't exist." );
	//sContestProblemData contest_problem_data;
	//if( !ContestProblemDataBase->GetByKey( contest_contestant_problem_data.ContestProblemId, contest_problem_data ) )
	//	return ErrorHtml( client_data, "ContestProblem doesn't exist." );
	//sProblemData problem_data;
	//if( !ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
	//	return ErrorHtml( client_data, "Problem doesn't exist." );
	//sLanguageData language_data;
	//if( !LanguageDataBase->GetByKey( contest_contestant_problem_data.LanguageId, language_data ) )
	//	return ErrorHtml( client_data, "Language doesn't exist." );
	// Проверка прав доступа к странице
	//if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING || contest_contestant_data.ContestantId == client_data.ContestantId ) )
	//	return ErrorHtml( client_data, "You have no permission for this page." );
	// Чтение из базы
	string code;
	if( !ContestContestantProblemDataFile.LoadStringAndFlush( contest_contestant_problem_data.Code, contest_contestant_problem_data.CodeSize, code ) )
		return ErrorHtml( client_data, "Unable to load source code from file." );
	string compilation_error;
	if( !ContestContestantProblemDataFile.LoadStringAndFlush( contest_contestant_problem_data.CompilationError, contest_contestant_problem_data.CompilationErrorSize, compilation_error ) )
		return ErrorHtml( client_data, "Unable to load compilation error from file." );
	// Генерация страницы
	string result;
	result += "<center>";

//	result += StringPrintf( "<a href='/contest_contestant.html?contest_contestant_id=%lu'><h1 class='title'>%s</h1></a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
	sContestContestantData contest_contestant_data;
	if( ContestContestantDataBase->GetByKey( contest_contestant_problem_data.ContestContestantId, contest_contestant_data ) )
	{
		if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING || contest_contestant_data.ContestantId == client_data.ContestantId ) )
			return ErrorHtml( client_data, "You have no permission for this page." );
		sContestData contest_data;
		if( ContestDataBase->GetByKey( contest_contestant_data.ContestId, contest_data ) )
			result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><h1 class='title'>%s</h1></a>", contest_contestant_data.ContestId, Escape( contest_data.Title ).c_str() );
		else
			result += StringPrintf( "<a href='/contest.html?contest_id=%lu'><font class='error'><h1 class='title'>Error</h1></font></a>", contest_contestant_data.ContestId );
		result += "<hr>";
		sContestantData contestant_data;
		if( ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
			result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
		else
			result += StringPrintf( "<a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'><font class='error'>Error</font></a>", contest_contestant_data.Key );
	}
	else
	{
		result += StringPrintf( "<font class='error'><h1 class='title'>Error</h1></font>" );
		result += "<hr>";
		if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
			return ErrorHtml( client_data, "You have no permission for this page." );
		result += StringPrintf( "<font class='error'>Error</font>" );
	}
	result += "<hr>";

//	result += StringPrintf( "<a class='record' href='/contest_problem_frame.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	//result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.Key, Escape( contest_problem_data.Letter ).c_str(), problem_data.Header );
	sContestProblemData contest_problem_data;
	if( ContestProblemDataBase->GetByKey( contest_contestant_problem_data.ContestProblemId, contest_problem_data ) )
	{
		sProblemData problem_data;
		if( ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
			result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. %s</a>", contest_problem_data.ProblemId, contest_problem_data.Letter, problem_data.Header );
		else
			result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. <font class='error'>Error</font></a>", contest_contestant_problem_data.ContestProblemId, contest_problem_data.Letter );
	}
	else
		result += StringPrintf( "<a class='record' href='/contest_problem.html?contest_problem_id=%lu'><font class='error'>Error</font></a>", contest_contestant_problem_data.ContestProblemId );
	result += "<hr>";
	result += "<table cellspacing='0'>";

	result += "<tr>";
	result += "<td class='variable_name'>Relative time</td>";
	result += StringPrintf( "<td class='variable_value'>%lu:%02lu:%02lu</td>", contest_contestant_problem_data.RelativeTime / 60 / 60, contest_contestant_problem_data.RelativeTime / 60 % 60, contest_contestant_problem_data.RelativeTime % 60 );
	result += "</tr>";

	unsigned short year, month, day, day_of_week, hour, minute, second, millisecond;
	SplitTime( contest_contestant_problem_data.RealTime, &year, &month, &day, &day_of_week, &hour, &minute, &second, &millisecond );
	result += "<tr>";
	result += "<td class='variable_name'>Real time</td>";
	result += StringPrintf( "<td class='variable_value'>%hu:%02hu:%02hu&nbsp;&nbsp;&nbsp;%s,&nbsp;%hu&nbsp;%s&nbsp;%hu</td>", hour, minute, second, DayOfWeekName[ day_of_week ], day, MonthName[ month - 1 ], year );
	result += "</tr>";

	result += "<tr>";
	result += "<td class='variable_name'>Language</td>";
	sLanguageData language_data;
	if( contest_contestant_problem_data.LanguageId == BAD_KEY )
		result += StringPrintf( "<td class='record' align='center'>Undefined</td>" );
	else if( LanguageDataBase->GetByKey( contest_contestant_problem_data.LanguageId, language_data ) )
		result += StringPrintf( "<td class='variable_value'>%s</td>", language_data.Title );
	else
		result += StringPrintf( "<td class='variable_value'><font class='error'>Error</font></td>", language_data.Title );
	result += "</tr>";

	result += "<tr>";
	result += "<td class='variable_name'>Result</td>";
	result += StringPrintf( "<td class='variable_value'>%s</td>", GetResult( contest_contestant_problem_data ).c_str() );
	result += "</tr>";

	result += "<tr>";
	result += "<td class='variable_name'>Running time</td>";
	result += StringPrintf( "<td class='variable_value'>%.3lf</td>", ( double )contest_contestant_problem_data.RunTime / 1000 );
	result += "</tr>";

	result += "<tr>";
	result += "<td class='variable_name'>Used memory</td>";
	result += StringPrintf( "<td class='variable_value'>%lu&nbsp;kB</td>", contest_contestant_problem_data.Memory / 1024 );
	result += "</tr>";

	if( client_contestant_data.Status & STATUS_CONTEST_EDITING )
	{
		result += "<tr>";
		result += "<td class='variable_name'>Ip</td>";
		result += StringPrintf( "<td class='variable_value'>%lu.%lu.%lu.%lu</td>", contest_contestant_problem_data.Ip >> 24 & 0xff, contest_contestant_problem_data.Ip >> 16 & 0xff, contest_contestant_problem_data.Ip >> 8 & 0xff, contest_contestant_problem_data.Ip >> 0 & 0xff );
		result += "</tr>";
	}

	result += "</table>";
	if( contest_contestant_problem_data.Result == RESULT_COMPILATION_ERROR && compilation_error.length() != 0 )
	{
		result += StringPrintf( "<pre class='compilation_error'>%s</pre>", Escape( compilation_error ).c_str() );
	}
	result += StringPrintf( "<pre class='code'>%s</pre>", Escape( code ).c_str() );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}

std::string ContestantContestProblemsHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	int start, finish, count;
	InitializeControlVariables( start, finish, count, parameter );
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<table cellspacing='0' width='100%'>";
	result += "<tr>";
	result += "<th class='list'>#</th>";
	result += "<th class='list'>Time</th>";
	result += "<th class='list'>Contestant</th>";
	result += "<th class='list'>Problem</th>";
	result += "<th class='list'>Language</th>";
	result += "<th class='list'>Result</th>";
	result += "<th class='list'>Time</th>";
	result += "<th class='list'>Memory</th>";
	result += "<th class='list'>&nbsp;</th>";
	result += "</tr>";
	{
		cLocker contestant_locker( *ContestantDataBase );
		cLocker language_locker( *LanguageDataBase );
		cLocker contest_contestant_locker( *ContestContestantDataBase );
		cLocker contest_contestant_problem_locker( *ContestContestantProblemDataBase );
		nsContestContestantProblemDataBase::KeyReverseIterator contest_contestant_problem_iterator = ContestContestantProblemDataBase->ReverseBeginByKey(), contest_contestant_problem_end = ContestContestantProblemDataBase->ReverseEndByKey();
		int number = contest_contestant_problem_end - contest_contestant_problem_iterator;
		for( ; contest_contestant_problem_iterator != contest_contestant_problem_end; ++contest_contestant_problem_iterator, --number )
		{
			if( start <= count && count < finish )
			{
				result += "<tr class='record'>";
				result += StringPrintf( "<td class='record' align='right'>%d.</td>", number );
				result += StringPrintf( "<td class='record' align='center'>%lu:%02lu:%02lu</td>", contest_contestant_problem_iterator->RelativeTime / 60 / 60, contest_contestant_problem_iterator->RelativeTime / 60 % 60, contest_contestant_problem_iterator->RelativeTime % 60 );
				sContestContestantData contest_contestant_data;
				sContestantData contestant_data;
				if( ContestContestantDataBase->GetByKey( contest_contestant_problem_iterator->ContestContestantId, contest_contestant_data ) )
					if( ContestantDataBase->GetByKey( contest_contestant_data.ContestantId, contestant_data ) )
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'>%s</a></td>", contest_contestant_data.Key, Escape( contestant_data.Name ).c_str() );
					else
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_contestant.html?contest_contestant_id=%lu'><font class='error'>Error</font></a></td>", contest_contestant_data.Key );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				sContestProblemData contest_problem_data;
				sProblemData problem_data;
				if( ContestProblemDataBase->GetByKey( contest_contestant_problem_iterator->ContestProblemId, contest_problem_data ) )
					if( ProblemDataBase->GetByKey( contest_problem_data.ProblemId, problem_data ) )
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/problem.html?problem_id=%lu'>%s. %s</a></td>", problem_data.Key, contest_problem_data.Letter, problem_data.Header );
					else
						result += StringPrintf( "<td class='record' align='center'><a class='record' href='/contest_problem.html?contest_problem_id=%lu'>%s. <font class='error'>Error</font></a></td>", contest_problem_data.Key, contest_problem_data.Letter );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				sLanguageData language_data;
				if( contest_contestant_problem_iterator->LanguageId == BAD_KEY )
					result += StringPrintf( "<td class='record' align='center'>Undefined</td>" );
				else if( LanguageDataBase->GetByKey( contest_contestant_problem_iterator->LanguageId, language_data ) )
					result += StringPrintf( "<td class='record' align='center'>%s</td>", language_data.Title );
				else
					result += StringPrintf( "<td class='record' align='center'><font class='error'>Error</font></td>" );
				result += StringPrintf( "<td class='record' align='center'>%s</td>", GetResult( *contest_contestant_problem_iterator ).c_str() );
				result += StringPrintf( "<td class='record' align='center'>%.3lf</td>", ( double )contest_contestant_problem_iterator->RunTime / 1000 );
				if( contest_contestant_problem_iterator->Memory < 1024000 )
					result += StringPrintf( "<td class='record' align='center'>%lu&nbsp;kB</td>", contest_contestant_problem_iterator->Memory / 1024 );
				else
					result += StringPrintf( "<td class='record' align='center'>%.2lf&nbsp;MB</td>", ( double )contest_contestant_problem_iterator->Memory / 1048576 );
				result += "<td class='record' align='center'>";
				result += StringPrintf( "<a class='command' href='/rejudge.action?contest_contestant_problem_id=%lu'><img class='command' src='/refresh.png' alt='rejudge' title='Rejudge submission'></a>", contest_contestant_problem_iterator->Key );
				result += StringPrintf( "<a class='command' href='/contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/info.png' alt='info' title='View info'></a>", contest_contestant_problem_iterator->Key );
				result += StringPrintf( "<a class='command' href='/edit_contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/pencil.png' alt='edit' title='Edit submission'></a>", contest_contestant_problem_iterator->Key );
				result += StringPrintf( "<a class='command' href='/delete_contest_contestant_problem.html?contest_contestant_problem_id=%lu'><img class='command' src='/cross.png' alt='delete' title='Delete submission'></a>", contest_contestant_problem_iterator->Key );
				result += "</td>";
				result += "</tr>";
			}
			++count;
		}
	}
	result += "</table>";
	result += TableControlBar( start, finish, count, parameter );
	result += RefreshBar( parameter );
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result ); 
}

std::string AboutHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<p>ACM Server is a server for holding virtual contests by the ACM rules. The contest may base on problems of the most popular problem achives with online judge system such as Timus Online Judge, UVa Online Judge or Peking University Online Judge System. Visit acm-server.ru for downloads and updates.</p>";
	result += StringPrintf( "<p>Version: %s</p>", Version );
   result += "<p>Copyright &copy; 2008  Victor Vinogradov (fly3333@gmail.com)</p>";
   result += "<p>This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.</p>";
   result += "<p>This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.</p>";
	result += "<p>You should have received a copy of the GNU General Public License along with this program. If not, see <a href='http://www.gnu.org/licenses/'>http://www.gnu.org/licenses/</a>.</p>";
	return MainHtml( client_contestant_data, parameter, result ); 
}

std::string UploadContestHtml( const sClientData &client_data, const cFormat parameter )
{
	// Получение информации о клиенте
	sContestantData client_contestant_data;
	GetContestantDataById( client_data.ContestantId, client_contestant_data );
	// Проверка прав доступа к странице
	if( !( client_contestant_data.Status & STATUS_CONTEST_EDITING ) )
		return ErrorHtml( client_data, "You have no permission for this page." );
	// Извлечение параметров
	// Чтение из базы
	// Генерация страницы
	string result;
	result += "<center>";
	result += "<h1 class='title'>Upload contest</h1>";
	result += "<form action='/upload_contest.action' method='post' enctype='multipart/form-data'>";
	result += "<table class='edit' cellspacing='0' align='center'>";
	result += "<tr>";
	result += "<td class='edit_field_name'>File of contest:</td>";
	result += "<td class='edit_field_value'><input class='file' type='file' name='file' size='50'></td>";
	result += "</tr>";
	result += "</table>";
	result += "<input type='submit' class='submit' value='Upload'>";
	result += "</form>";
	result += "</center>";
	return MainHtml( client_contestant_data, parameter, result );
}
